在关系型数据库中,表与表之间往往有一定的关联,允许其信息在整个数据库中只写一次。然后,当你需要分析数据时,你就需要把这些相关表的信息结合起来。
要在SQL中做到这一点,你可以使用JOIN 语句。LEFT JOIN 语句是可用的各种JOIN 语句中的一种。当你使用它来连接两个表时,它会保留第一个表(左表)的所有行,即使在第二个表上没有相应的匹配。
你可以在SELECT 查询中使用JOIN 来连接两个表,table_1 和table_2 ,像这样:
SELECT columns
FROM table_1
LEFT OUTER JOIN table_2
ON relation;
SELECT columns
FROM table_1
LEFT JOIN table_2
ON relation;
首先你要写出哪些列会出现在连接的表中。你可以通过在列名前加上表名来指定该列属于哪个表。如果一些列的名称相同(如table_1.column_1 和table_2.column_1 ),这是有必要的,SELECT <columns> 。
那么你会把第一个表的名字写成FROM table_1 。
之后,你会把第二个表的名字写成LEFT OUTER JOIN table_2 或LEFT JOIN table_2 (省略OUTER 关键字)。
在最后,你会写上用来匹配行的关系,例如:ON table_1.column_A = table_2.column_B 。通常情况下,关系是通过id,但也可以是任何列。
SQL LEFT JOIN例子
假设你有一个图书数据库,其中有两个表,一个是图书,另一个是作者。为了避免重复每本书的作者信息,这些信息在自己的表中,而书中只有author_name 列。
| book_id | 标题 | 作者姓名 | 出版年份 |
|---|---|---|---|
| 1 | 一,二,三,四,五 | 路易吉-皮兰德娄 | 1926 |
| 2 | 我的眼睛》(Il visconte dimezzato | 伊塔罗-卡尔维诺 | 1952 |
| 3 | 莫泊桑的老虎》(Le tigri di Mompracem | 埃米利奥-萨尔加里 | 1900 |
| 4 | 狸猫之日 | 莱昂纳多-西亚斯奇亚 | 1961 |
| 5 | 对所有的人都是如此 | 莱昂纳多-西亚斯基亚 | 1966 |
| 6 | 他是马蒂亚-帕斯卡尔 | 路易吉-皮兰德娄 | 1904 |
| 7 | I Malavoglia | Giovanni Verga | 1881 |
| 作者_id | 姓名 | 出生年份 | 出生地 | 琐事 |
|---|---|---|---|---|
| 1 | 路易吉-皮兰德娄 | 1867 | 阿格里琴托 | 1934年获诺贝尔文学奖 |
| 2 | 乔瓦尼-维尔加 | 1840 | 维齐尼 | 1920年至1922年任意大利王国参议员 |
| 3 | 伊塔洛-斯维沃 | 1861 | 的里雅斯特 | 本名阿隆-赫克托-施米茨 |
| 4 | 切萨雷-帕维斯 | 1908 | 圣斯蒂法诺-贝尔博 | 无名氏 |
| 5 | Giuseppe Tomasi di Lampedusa | 1896 | 巴勒莫 | 1934年至1957年期间担任兰佩杜萨的王子 |
我们可以根据作者的名字来连接这两个表。使用books 表作为左表,你可以写出以下代码来连接它们:
SELECT books.title AS book_title, books.publ_year, books.author_name, authors.year_of_birth, authors.place_of_birth
FROM books
LEFT JOIN authors
ON books.author_name = authors.name
;
让我们把它分解一下。
在第一行,你选择在最后的表中显示哪些列。这也是决定某些列是否会在使用AS 的结果表中有一个不同的名字的地方,就像使用books.title AS book_title 一样。
第二行,FROM books ,说明哪一个是要考虑的第一个表,也叫左表。
然后第三行,LEFT JOIN authors ,说明要考虑哪一个表。
ON books.author_name = authors.name 第3行: 和 ,说的是用这两张表来匹配。books.author_name authors.name
经过这个查询,你会得到如下表格,其中没有从作者表中得到信息的行只显示NULL :
| book_title | 出版年份 | 作者姓名 | 出生年月 | 出生地 |
|---|---|---|---|---|
| 一,二,三,四,五,六 | 1926 | 路易吉-皮兰德娄 | 1867 | 阿格里琴托 |
| 视觉障碍 | 1952 | 伊塔罗-卡尔维诺 | 无 | 无 |
| 莫泊桑的老虎》(Le tigri di Mompracem | 1900 | 埃米利奥-萨尔加里 | 详见 | 不适用 |
| 狸猫之日 | 1961 | 莱昂纳多-沙斯卡亚 | 冇 | ǞǞǞ |
| 对所有的人都是如此 | 1966 | Leonardo Sciascia | ǞǞǞ | ǞǞǞ |
| 他是马蒂亚-帕斯卡尔 | 1904 | 路易吉-皮兰德娄 | 1867 | 阿格里琴托 |
| I Malavoglia | 1881 | 乔瓦尼-维尔加 | 1840 | 维兹尼 |
请注意,在books 表中不存在的作者不在这个连接表中。这是因为,正如我之前所说,只保留了左表(在这种情况下是books )中不相关的行,而没有保留右表/第二表的行。
一个更复杂的 LEFT JOIN 例子
让我们看看另一种方法,你可以使用JOIN 和其他SQL功能来做一些数据分析。
你可能想看看数据库里有多少本来自每个作者的书。你可以使用下面的查询来完成这个任务:
SELECT authors.name AS author_name,
SUM(
CASE
WHEN books.title LIKE '%'
THEN 1
ELSE 0
END
) as number_of_books
FROM authors
LEFT JOIN books
ON books.author_name = authors.name
GROUP BY authors.name
ORDER BY number_of_books DESC
;
代码分解
第1行:用SELECT ,你在结果表中列出你想要的列。
第2行:SUM 是一个聚合函数,与GROUP BY结合使用。被分组的行的值然后被加总。
第3-7行:你使用CASE语句,根据一个条件得到不同的结果。在本例中,如果某行包含书名,则算作1,否则算作0。这里我们使用LIKE ,检查单元格是否包含任何字符(在这篇文章中了解更多关于包含字符串的内容)。
第8行:这给为SUM创建的列起了一个名字:number_of_books 。
第9行:本例中的左/第一张表是authors 。
第10行:在这种情况下,右边/第二张表是books 。
第11行:使用作者姓名连接这两个表。
第12行:行被按作者姓名分组--所有在该列中具有相同值的行将被代表在一个行中。
第13行:我们使用order by,用书的数量进行降序排列。
该查询将给你提供以下表格。请注意,你在这里看到的只是在authors 表中出现的作者。books 表中提到的作者,如果在authors 表中没有条目,这里就不存在。这是由于没有保留books 表中不相关的行所产生的影响:
| 作者姓名 | 书籍数量 |
|---|---|
| 路易吉-皮兰德娄 | 2 |
| Giovanni Verga | 1 |
| Cesare Pavese | 0 |
| Giuseppe Tomasi di Lampedusa | 0 |
| 伊塔洛-斯维沃 | 0 |
如果更新authors 表,以包括books 表中提到的所有作者,像这样:
| author_id | 姓名 | 出生年份 | 出生地 | 琐事 |
|---|---|---|---|---|
| 1 | 路易吉-皮兰德娄 | 1867 | 阿格里琴托 | 1934年获诺贝尔文学奖 |
| 2 | 乔瓦尼-维尔加 | 1840 | 维齐尼 | 1920年至1922年任意大利王国参议员 |
| 3 | 伊塔洛-斯维沃 | 1861 | 的里雅斯特 | 本名阿隆-赫克托-施密茨 |
| 4 | 切萨雷-帕维斯 | 1908 | 圣斯蒂法诺-贝尔博 | 无名氏 |
| 5 | Giuseppe Tomasi di Lampedusa | 1896 | 巴勒莫 | 1934年至1957年担任兰佩杜萨的亲王 |
| 6 | 伊塔罗-卡尔维诺 | 1923 | 圣地亚哥-德拉斯维加斯 | 不详 |
| 7 | 埃米利奥-萨尔加里 | 1862 | 维罗纳 | 不详 |
| 8 | Leonardo Sciascia | 1921 | 拉卡尔穆托 | NULL |
那么上面的查询表实际上会给出所有作者的书的数量:
| 作者姓名 | 书籍数量 |
|---|---|
| Leonardo Sciascia | 2 |
| 路易吉-皮兰德娄 | 2 |
| 埃米利奥-萨尔加里 | 1 |
| Giovanni Verga | 1 |
| 乔瓦尼-维尔加 | 1 |
| Cesare Pavese | 0 |
| Giuseppe Tomasi di Lampedusa | 0 |
| 伊塔洛-斯维沃 | 0 |
结论
在关系型数据库中,数据应该只写一次,所以我们经常会有多个相互关联的表。当我们需要分析数据和连接来自不同表的信息时,LEFT JOIN 是一个非常有用的盟友。享受使用这个强大的工具来查询你的数据库。