子查询

SELECT 是查询语句,但 SQL 还支持 SELECT 的嵌套使用,这种使用称之为子查询。后面我将介绍子查询的三种应用:子查询作为筛选条件、子查询作为计算字段、使用子查询插入。需要注意的是,这些仅是子查询的常见应用,子查询不止可以用于这些场景。另外子查询尽管提供了很好的自由度,但很多时候效率低下,在可以使用下一章介绍的联结时尽量使用联结。

子查询作为筛选条件

可以将子查询作为筛选条件,这通常使用 IN 多值查找,但这要求子查询的返回必须只有一列。

1
{SELECT 语句} WHERE {字段} IN ({SELECT 子查询})

HAVING 分组筛选同理。

1
2
3
4
5
6
7
8
9
SELECT 
*
FROM
movies
WHERE
title IN (
SELECT movieTitle FROM StarsIn
);
-- 查找所有有明星出演的电影信息(所有明星出演作品都会在 StarsIn 中)
1
2
3
4
5
6
7
8
+---------------------+------+--------+-----------+------------+-----------+
| title | year | length | movieType | studioName | producerC |
+---------------------+------+--------+-----------+------------+-----------+
| Empire Strikes Back | 1980 | 111 | drama | Fox | 555 |
| Star Wars | 1977 | 124 | sciFic | Fox | 555 |
| Terms of Endearment | 1983 | 132 | drama | MGM | 123 |
| The Usual Suspects | 1995 | 106 | drama | MGM | 999 |
+---------------------+------+--------+-----------+------------+-----------+

当然你也可以使用子查询进行条件筛选,但不适用多值查找,这时要求子查询返回仅一个单元格(或 Empty Set),在此不作举例。

子查询作为计算字段

与计算字段在 SELECT 语句中填写一个表达式类似,子查询作为计算字段时即对每行计算一个值,因此该子查询的返回要求仅一个单元格(或 Empty Set)。

1
SELECT {SELECT 子查询} [AS {别名}] FROM {表名};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
SELECT 
title,
year,
length,
movieType,
studioName,
(
SELECT
address
FROM
studio
WHERE
name = studioName
) AS studioAddress
FROM
movies;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
+--------------------------+------+--------+-----------+----------------+--------------------------+
| title | year | length | movieType | studioName | studioAddress |
+--------------------------+------+--------+-----------+----------------+--------------------------+
| Empire Strikes Back | 1980 | 111 | drama | Fox | Fox Boulevard |
| My people,My country | 2019 | 158 | feature | huaxia | Boulevard |
| Gone With the Wind | 1938 | 238 | drama | MGM | MGM Boulevard |
| Logan's run | 1977 | 120 | drama | MGM | MGM Boulevard |
| Pretty Woman | 1990 | 119 | drama | Disney | Disney Boulevard |
| Star Trek | 1979 | NULL | sciFic | Paramount | Paramount Boulevard |
| Star Trek: Nemesis | 2002 | 116 | sciFic | Paramount | Paramount Boulevard |
| Star Wars | 1977 | 124 | sciFic | Fox | Fox Boulevard |
| Terms of Endearment | 1983 | 132 | drama | MGM | MGM Boulevard |
| The Man Who Wasn't There | 2001 | 116 | comedy | USA Entertainm | USA Entertainm Boulevard |
| The Usual Suspects | 1995 | 106 | drama | MGM | MGM Boulevard |
+--------------------------+------+--------+-----------+----------------+--------------------------+

使用子查询插入或创建

可以使用子查询进行快速插入,这常用于快速创建一张表。

1
2
INSERT INTO {表名} {SELECT 子查询}
-- INSERT INTO NewMovieExec SELECT * FROM MovieExec;

相似地,也可以使用子查询直接创建表。

1
2
CREATE TABLE {表名} {SELECT 子查询}
-- CREATE TABLE NewMovieExec SELECT * FROM MovieExec;

子查询效率低下的情形

尽管子查询高度自由、功能强大,但有时候子查询却效率低下。在将子查询作为计算字段时,对每一行我们都需要执行查询语句。然而在另一张表中查询一个值的代价也是高昂的,这导致了将子查询作为计算字段时,时间复杂度可能是 O(nm)O(nm) 的,即两张表的行数的乘积。这也是为什么建议尽量使用联结,而不是子查询。

一个关于子查询效率低下的示例

需要注意的是,由于 SQL 可能会尝试优化你的子查询,你可能无法很快找到一个效率低下的示例。

假设我们已经创建了一张 1e5 级别的表,先展示一下这张表。

1
2
SELECT COUNT(*) FROM test;
SHOW CREATE TABLE test;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
+----------+
| COUNT(*) |
+----------+
| 511232 |
+----------+
1 row in set (0.02 sec)

-- 仅摘取部分
test | CREATE TABLE `test` (
`id` int NOT NULL,
`name` varchar(255) DEFAULT NULL,
`age` int DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `NameIndex` (`name`(4))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci

现在开始测试一个子查询语句。

1
2
3
4
5
6
7
8
9
10
11
12
SELECT 
(
SELECT
b.name
FROM
test AS b
WHERE
a.id = b.id-1
),
a.name
FROM
test AS a;
1
-- 本机 1 个多小时都没跑出结果...

其实子查询可以分为:相关子查询、独立子查询。相关子查询是指在子查询中,依赖子查询外部的变量;独立子查询是指在子查询中,与外部变量无关。很容易理解,无论外部如何变化,独立子查询都返回相同结果。因此独立子查询很好优化,通常只需作一次计算,时间复杂度为 O(n+m)O(n+m);而相关子查询则变得效率低下,时间复杂度为 O(nm)O(nm)

关于子查询作多值查找效率的问题

然而当子查询作为筛选条件时,使用 IN 多值查找可能产生很大的匹配集,不过这部分优化做的比较好,依然可以保持一个很好的效率,具体原理我目前也不是很清楚。

网络查找了相关资料,无一例外均解释 IN 多值查找为顺序查找。但是我做了下面这个测试:

1
SELECT * FROM test_index AS a WHERE a.id IN (SELECT b.id ^ 1000 FROM test_index AS b);
1
510976 rows in set (2.38 sec)

如果 IN 是对数据进行排序作二分查找,那么可以理解其高效,但相关资料都解释其为顺序查找。不是很清楚 MySQL 是如何做到在顺序查找下做到如此优秀的时间的。更进一步可能需要去看源码了。

联结 JOIN

什么是联结?

联结就是将两张表的信息连接起来,但是我们为什么不直接将所有信息存贮在一张表中呢?这样做与直接在表中存储所有信息的区别是可以减少内存的占用,同时保证信息的一致性。例如:我们有一张学生表表存储学生的个人信息,例如年龄、生日、家乡等,但学生同时被引用于多个表,如学生组织、班级名单、课程的点名册。这时我们只需在这些引用学生信息的表中留下学生学号,需要时再通过学生表查找该学生的其他信息。设想如果我们将学生的详细信息拷贝到每张表中,将极大增加存储的负担,同时增加信息维护的难度,因为我们需要确保多个拷贝中的信息是一致的。

其实联结很简单,简单来说就是对两个表求笛卡尔积。所谓笛卡尔积就是求两表所有行的组合,假设左表有 nn 行记录、右表有 mm 行记录,则两表的笛卡尔积有 nmnm 行记录。需要注意的是,和计算字段一样,所有联结数据表都不是物理的。

1
SELECT * FROM MovieStar;
1
SELECT * FROM StarsIn;
1
SELECT * FROM MovieStar, StarsIn;  -- 笛卡尔积
1
2
3
4
5
6
7
8
9
10
11
+----------------+-------------+--------+------------+
| name | address | gender | birthDate |
+----------------+-------------+--------+------------+
| Alec Baldwin | Baldwin Av. | M | 1977-06-07 |
| Kim Basinger | Baldwin Av. | F | 1979-05-07 |
| Debra Winger | A way | F | 1978-05-06 |
| Harrison Ford | Prefect Rd. | M | 1955-05-05 |
| Jack Nicholson | X path | M | 1949-05-05 |
| Jane Fonda | Turner Av. | F | 1977-07-07 |
+----------------+-------------+--------+------------+
6 rows in set (0.00 sec)
1
2
3
4
5
6
7
8
9
10
11
12
+---------------------+-----------+----------------+
| movieTitle | movieYear | starName |
+---------------------+-----------+----------------+
| Empire Strikes Back | 1980 | Harrison Ford |
| Star Wars | 1977 | Carrie Fisher |
| Star Wars | 1977 | Harrison Ford |
| Star Wars | 1977 | Mark Hamill |
| Terms of Endearment | 1983 | Debra Winger |
| Terms of Endearment | 1983 | Jack Nicholson |
| The Usual Suspects | 1995 | Kevin Spacey |
+---------------------+-----------+----------------+
7 rows in set (0.00 sec)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
+----------------+-------------+--------+------------+---------------------+-----------+----------------+
| name | address | gender | birthDate | movieTitle | movieYear | starName |
+----------------+-------------+--------+------------+---------------------+-----------+----------------+
| Jane Fonda | Turner Av. | F | 1977-07-07 | Empire Strikes Back | 1980 | Harrison Ford |
| Jack Nicholson | X path | M | 1949-05-05 | Empire Strikes Back | 1980 | Harrison Ford |
| Harrison Ford | Prefect Rd. | M | 1955-05-05 | Empire Strikes Back | 1980 | Harrison Ford |
| Debra Winger | A way | F | 1978-05-06 | Empire Strikes Back | 1980 | Harrison Ford |
| Kim Basinger | Baldwin Av. | F | 1979-05-07 | Empire Strikes Back | 1980 | Harrison Ford |
| Alec Baldwin | Baldwin Av. | M | 1977-06-07 | Empire Strikes Back | 1980 | Harrison Ford |
| Jane Fonda | Turner Av. | F | 1977-07-07 | Star Wars | 1977 | Carrie Fisher |
| Jack Nicholson | X path | M | 1949-05-05 | Star Wars | 1977 | Carrie Fisher |
| Harrison Ford | Prefect Rd. | M | 1955-05-05 | Star Wars | 1977 | Carrie Fisher |
| Debra Winger | A way | F | 1978-05-06 | Star Wars | 1977 | Carrie Fisher |
| Kim Basinger | Baldwin Av. | F | 1979-05-07 | Star Wars | 1977 | Carrie Fisher |
| Alec Baldwin | Baldwin Av. | M | 1977-06-07 | Star Wars | 1977 | Carrie Fisher |
| Jane Fonda | Turner Av. | F | 1977-07-07 | Star Wars | 1977 | Harrison Ford |
| Jack Nicholson | X path | M | 1949-05-05 | Star Wars | 1977 | Harrison Ford |
| Harrison Ford | Prefect Rd. | M | 1955-05-05 | Star Wars | 1977 | Harrison Ford |
| Debra Winger | A way | F | 1978-05-06 | Star Wars | 1977 | Harrison Ford |
| Kim Basinger | Baldwin Av. | F | 1979-05-07 | Star Wars | 1977 | Harrison Ford |
| Alec Baldwin | Baldwin Av. | M | 1977-06-07 | Star Wars | 1977 | Harrison Ford |
| Jane Fonda | Turner Av. | F | 1977-07-07 | Star Wars | 1977 | Mark Hamill |
| Jack Nicholson | X path | M | 1949-05-05 | Star Wars | 1977 | Mark Hamill |
| Harrison Ford | Prefect Rd. | M | 1955-05-05 | Star Wars | 1977 | Mark Hamill |
| Debra Winger | A way | F | 1978-05-06 | Star Wars | 1977 | Mark Hamill |
| Kim Basinger | Baldwin Av. | F | 1979-05-07 | Star Wars | 1977 | Mark Hamill |
| Alec Baldwin | Baldwin Av. | M | 1977-06-07 | Star Wars | 1977 | Mark Hamill |
| Jane Fonda | Turner Av. | F | 1977-07-07 | Terms of Endearment | 1983 | Debra Winger |
| Jack Nicholson | X path | M | 1949-05-05 | Terms of Endearment | 1983 | Debra Winger |
| Harrison Ford | Prefect Rd. | M | 1955-05-05 | Terms of Endearment | 1983 | Debra Winger |
| Debra Winger | A way | F | 1978-05-06 | Terms of Endearment | 1983 | Debra Winger |
| Kim Basinger | Baldwin Av. | F | 1979-05-07 | Terms of Endearment | 1983 | Debra Winger |
| Alec Baldwin | Baldwin Av. | M | 1977-06-07 | Terms of Endearment | 1983 | Debra Winger |
| Jane Fonda | Turner Av. | F | 1977-07-07 | Terms of Endearment | 1983 | Jack Nicholson |
| Jack Nicholson | X path | M | 1949-05-05 | Terms of Endearment | 1983 | Jack Nicholson |
| Harrison Ford | Prefect Rd. | M | 1955-05-05 | Terms of Endearment | 1983 | Jack Nicholson |
| Debra Winger | A way | F | 1978-05-06 | Terms of Endearment | 1983 | Jack Nicholson |
| Kim Basinger | Baldwin Av. | F | 1979-05-07 | Terms of Endearment | 1983 | Jack Nicholson |
| Alec Baldwin | Baldwin Av. | M | 1977-06-07 | Terms of Endearment | 1983 | Jack Nicholson |
| Jane Fonda | Turner Av. | F | 1977-07-07 | The Usual Suspects | 1995 | Kevin Spacey |
| Jack Nicholson | X path | M | 1949-05-05 | The Usual Suspects | 1995 | Kevin Spacey |
| Harrison Ford | Prefect Rd. | M | 1955-05-05 | The Usual Suspects | 1995 | Kevin Spacey |
| Debra Winger | A way | F | 1978-05-06 | The Usual Suspects | 1995 | Kevin Spacey |
| Kim Basinger | Baldwin Av. | F | 1979-05-07 | The Usual Suspects | 1995 | Kevin Spacey |
| Alec Baldwin | Baldwin Av. | M | 1977-06-07 | The Usual Suspects | 1995 | Kevin Spacey |
+----------------+-------------+--------+------------+---------------------+-----------+----------------+
42 rows in set (0.00 sec)

但是我们也看到了,在上面这个 4242 行记录的表并没有什么实际意义,因此联结通常与筛选混用。

1
2
3
4
5
6
7
8
9
10
SELECT 
movieTitle,
movieYear,
M.*
FROM
StarsIn AS S,
MovieStar AS M
WHERE
S.starName = M.name;
-- 筛选所有明星出演的电影, 并显示明星的详细信息
1
2
3
4
5
6
7
8
+---------------------+-----------+----------------+-------------+--------+------------+
| movieTitle | movieYear | name | address | gender | birthDate |
+---------------------+-----------+----------------+-------------+--------+------------+
| Empire Strikes Back | 1980 | Harrison Ford | Prefect Rd. | M | 1955-05-05 |
| Star Wars | 1977 | Harrison Ford | Prefect Rd. | M | 1955-05-05 |
| Terms of Endearment | 1983 | Debra Winger | A way | F | 1978-05-06 |
| Terms of Endearment | 1983 | Jack Nicholson | X path | M | 1949-05-05 |
+---------------------+-----------+----------------+-------------+--------+------------+

内联结与外联结

其实上面我们介绍的这种使用 WHERE 的联结方式就是内联结。但 SQL 提供了一套联结的专用语法,内联结的关键字为 INNER JOIN

1
SELECT {字段...} FROM {主表} [INNER] JOIN {副表} [ON {条件表达式}]  -- 内联结

此外还有多种外联结,包括:LEFT JOIN (左联结) / RIGHT JOIN (右联结) / FULL JOIN (全联结)。

1
2
3
SELECT {字段...} FROM {主表} LEFT [OUTER] JOIN {副表} ON {条件表达式}  -- 左联结
SELECT {字段...} FROM {主表} RIGHT [OUTER] JOIN {副表} ON {条件表达式} -- 右联结
SELECT {字段...} FROM {主表} FULL [OUTER] JOIN {副表} ON {条件表达式} -- 全联结

它们的区别在于:内联结 简单的返回条件表达式中匹配的行,而 外联结 如果一边的表中某些行没有在内联结中依然输出。其中 左联结 显示主表中未内联结的行,右联结 显示副表中未联结的行,全联结 是左右联结的效果之和。

下面我就以 内联结左联结 为例,来展示它们的区别。可以看到在外联结中,有许多的 NULL 行即为未匹配的行。

1
2
3
4
5
6
7
8
9
SELECT 
movieTitle,
movieYear,
M.*
FROM
StarsIn AS S
INNER JOIN
MovieStar AS M ON S.starName = M.name;
-- 内联结示例
1
2
3
4
5
6
7
8
9
SELECT 
movieTitle,
movieYear,
M.*
FROM
StarsIn AS S
LEFT JOIN
MovieStar AS M ON S.starName = M.name;
-- 外联结示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
SELECT 
title,
year,
length,
movieType,
studioName,
address AS studioAddress,
starName
FROM
Movies AS M
INNER JOIN
Studio AS S ON studioName = name
LEFT JOIN
StarsIn ON title = movieTitle;
-- 联结的嵌套使用
1
2
3
4
5
6
7
8
+---------------------+-----------+----------------+-------------+--------+------------+
| movieTitle | movieYear | name | address | gender | birthDate |
+---------------------+-----------+----------------+-------------+--------+------------+
| Empire Strikes Back | 1980 | Harrison Ford | Prefect Rd. | M | 1955-05-05 |
| Star Wars | 1977 | Harrison Ford | Prefect Rd. | M | 1955-05-05 |
| Terms of Endearment | 1983 | Debra Winger | A way | F | 1978-05-06 |
| Terms of Endearment | 1983 | Jack Nicholson | X path | M | 1949-05-05 |
+---------------------+-----------+----------------+-------------+--------+------------+
1
2
3
4
5
6
7
8
9
10
11
+---------------------+-----------+----------------+-------------+--------+------------+
| movieTitle | movieYear | name | address | gender | birthDate |
+---------------------+-----------+----------------+-------------+--------+------------+
| Empire Strikes Back | 1980 | Harrison Ford | Prefect Rd. | M | 1955-05-05 |
| Star Wars | 1977 | NULL | NULL | NULL | NULL |
| Star Wars | 1977 | Harrison Ford | Prefect Rd. | M | 1955-05-05 |
| Star Wars | 1977 | NULL | NULL | NULL | NULL |
| Terms of Endearment | 1983 | Debra Winger | A way | F | 1978-05-06 |
| Terms of Endearment | 1983 | Jack Nicholson | X path | M | 1949-05-05 |
| The Usual Suspects | 1995 | NULL | NULL | NULL | NULL |
+---------------------+-----------+----------------+-------------+--------+------------+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
+--------------------------+------+--------+-----------+----------------+--------------------------+----------------+
| title | year | length | movieType | studioName | studioAddress | starName |
+--------------------------+------+--------+-----------+----------------+--------------------------+----------------+
| Empire Strikes Back | 1980 | 111 | drama | Fox | Fox Boulevard | Harrison Ford |
| My people,My country | 2019 | 158 | feature | huaxia | Boulevard | NULL |
| Gone With the Wind | 1938 | 238 | drama | MGM | MGM Boulevard | NULL |
| Logan's run | 1977 | 120 | drama | MGM | MGM Boulevard | NULL |
| Pretty Woman | 1990 | 119 | drama | Disney | Disney Boulevard | NULL |
| Star Trek | 1979 | NULL | sciFic | Paramount | Paramount Boulevard | NULL |
| Star Trek: Nemesis | 2002 | 116 | sciFic | Paramount | Paramount Boulevard | NULL |
| Star Wars | 1977 | 124 | sciFic | Fox | Fox Boulevard | Mark Hamill |
| Star Wars | 1977 | 124 | sciFic | Fox | Fox Boulevard | Harrison Ford |
| Star Wars | 1977 | 124 | sciFic | Fox | Fox Boulevard | Carrie Fisher |
| Terms of Endearment | 1983 | 132 | drama | MGM | MGM Boulevard | Jack Nicholson |
| Terms of Endearment | 1983 | 132 | drama | MGM | MGM Boulevard | Debra Winger |
| The Man Who Wasn't There | 2001 | 116 | comedy | USA Entertainm | USA Entertainm Boulevard | NULL |
| The Usual Suspects | 1995 | 106 | drama | MGM | MGM Boulevard | Kevin Spacey |
+--------------------------+------+--------+-----------+----------------+--------------------------+----------------+

另外多提一嘴,在 SQLite 中没有 RIGHT JOIN,此时只需简单替换主表和副表的位置然后使用 LEFT JOIN 即可。

自联结

自联结的概念独立于内联结和外联结,如果一个联结语句的主表和副表是同一张表,则称为自联结。自联结通常用于具有层次关系的表中,例如:员工表中有字段为领导 ID,但领导同样属于员工表,使用自联结可以显示领导的详细信息,而员工表则是一张描述这个树形结构并存储员工信息的表。自联结只是一种处理层次关系的概念,在语法上没有区分,此处不作示例。

自然联结

自然联结的关键字为 NATURAL JOIN,并且不能使用 ON 进行筛选。因为自然联结的含义是:自动推导筛选条件 。自然联结是一种内联结。自然联结会将两表中相同的字段作为条件联结,例如 A 表和 B 表中均有字段 nameaddress,则自动推导的筛选条件为 A.name=B.name AND A.address=B.address,另外显示时自动隐去 B 表中的相同字段。

1
SELECT * FROM MovieStar NATURAL JOIN MovieExec;
1
2
3
4
5
+------------+------------+--------+------------+------+-----------+
| name | address | gender | birthDate | cert | netWorth |
+------------+------------+--------+------------+------+-----------+
| Jane Fonda | Turner Av. | F | 1977-07-07 | 567 | 200000000 |
+------------+------------+--------+------------+------+-----------+

但是自然联结的局限性非常明显,因此实际很少使用它:

  • 无法联结需要的字段。自然联结强制字段名相同,但实际是例如:班级表中的学生字段为 studentID,学生表中的字段为 ID
  • 可能联结不要的字段。自然联结自动联结所有相同字段,但以上示例为例:两表都有 nameaddress 字段,当 name 字段相同而 address 字段不同时我们期望如何处理?可能我们需要优先遵从主表,但自然联结将直接去除该行。
  • 无法进行复杂条件联结。和前面一样,总之灵活性不足。

联结与子查询

现在我们来谈谈联结与子查询的区别和相同点。其实在前面的示例中,我们已经体现了联结和子查询的相似之处。那先来一个示例吧,下面三个代码的功能是一样的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
SELECT 
M.title,
M.year,
M.length,
M.movieType,
M.studioName,
(
SELECT
S.address
FROM
Studio AS S
WHERE
M.studioName = S.name
) AS studioAddress
FROM
Movies AS M
WHERE
M.studioName IN (
SELECT
S.name
FROM
Studio AS S
);
-- 子查询解决方案
1
2
3
4
5
6
7
8
9
10
11
12
13
SELECT 
M.title,
M.year,
M.length,
M.movieType,
M.studioName,
S.address AS studioAddress
FROM
Movies AS M,
Studio AS S
WHERE
M.studioName = S.name;
-- 笛卡尔积解决方案(也是联结, 但没用 JOIN)
1
2
3
4
5
6
7
8
9
10
11
12
SELECT 
M.title,
M.year,
M.length,
M.movieType,
M.studioName,
S.address AS studioAddress
FROM
Movies AS M
INNER JOIN
Studio AS S ON M.studioName = S.name;
-- 联结解决方案

三个输出是一样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
+--------------------------+------+--------+-----------+----------------+--------------------------+
| title | year | length | movieType | studioName | studioAddress |
+--------------------------+------+--------+-----------+----------------+--------------------------+
| Empire Strikes Back | 1980 | 111 | drama | Fox | Fox Boulevard |
| My people,My country | 2019 | 158 | feature | huaxia | Boulevard |
| Gone With the Wind | 1938 | 238 | drama | MGM | MGM Boulevard |
| Logan's run | 1977 | 120 | drama | MGM | MGM Boulevard |
| Pretty Woman | 1990 | 119 | drama | Disney | Disney Boulevard |
| Star Trek | 1979 | NULL | sciFic | Paramount | Paramount Boulevard |
| Star Trek: Nemesis | 2002 | 116 | sciFic | Paramount | Paramount Boulevard |
| Star Wars | 1977 | 124 | sciFic | Fox | Fox Boulevard |
| Terms of Endearment | 1983 | 132 | drama | MGM | MGM Boulevard |
| The Man Who Wasn't There | 2001 | 116 | comedy | USA Entertainm | USA Entertainm Boulevard |
| The Usual Suspects | 1995 | 106 | drama | MGM | MGM Boulevard |
+--------------------------+------+--------+-----------+----------------+--------------------------+

关于上面三种联结方案,我们可以总结如下:

  • 使用子查询方案显得非常愚蠢,在上面的示例中使用两个子查询才完成联结,并且在更复杂的情形两个还不够。在前面我们也提到了在使用子查询作为计算字段时可能极大降低效率,这种方法需要尽量避免。
  • 使用笛卡尔积的方案似乎在编码复杂性上和第三种方案差不多,并且它们的性能也基本没有差异,可以根据习惯选择。
  • 使用外联结时,JOIN 还是相对笛卡尔积方案方便的,在内联结时差不多,因此个人建议将编码习惯统一为使用 JOIN 关键字。