mysql多表联合查询

1. 多表联合查询

在关系型数据库中,表与表之间是有联系的,所以在实际应用中,经常使用多表查询。多表查询就是同时查询两个或两个以上的表。
在 MySQL 中,多表查询主要有交叉连接内连接外连接分组查询子查询等5种。

1.1 笛卡尔积

首先,先简单解释一下笛卡尔积。

有两个集合A和B。

A = {0,1} B = {2,3,4}

集合 A×B 和 B×A的结果集就可以分别表示为以下这种形式:

A×B = {(0,2),(1,2),(0,3),(1,3),(0,4),(1,4)};

B×A = {(2,0),(2,1),(3,0),(3,1),(4,0),(4,1)};

在上面A×B和B×A的结果就可以叫做两个集合相乘的笛卡尔积。

从以上的数据分析我们可以得出以下两点结论:

1,两个集合相乘,不满足交换率,既 A×B ≠ B×A;

2,A集合和B集合相乘,包含了集合A中元素和集合B中元素相结合的所有的可能性。既两个集合相乘得到的新集合的元素个数是 A集合的元素个数 × B集合的元素个数;

注意:

多表查询遵循的算法就是以上提到的笛卡尔积,表与表之间的连接可以看成是在做乘法运算。在实际应用中,应避免使用笛卡尔积,因为笛卡尔积中容易存在大量的不合理数据,简单来说就是容易导致查询结果重复、混乱。

案例:

现在有两张表 t_supert_song

t_super

mysql> select * from t_super;
+----+-----------+-----+-----+---------+
| id | name      | sex | age | song_id |
+----+-----------+-----+-----+---------+
|  1 | 谭咏麟    | 男  |  25 | 1       |
|  2 | 张国荣    | 男  |  23 | 2       |
|  3 | 林青霞    | 女  |  23 | 1       |
|  4 | 刘德华    | 男  |  22 | 3       |
|  5 | 张曼玉    | 女  |  24 | 2       |
|  6 | 邓丽君    | 女  |  21 | 4       |
|  7 | 张学友    | 男  |  22 | 4       |
|  8 | 黎明      | 男  |  23 | 5       |
|  9 | 梅艳芳    | 女  |  22 | 5       |
| 10 | 陈慧娴    | 女  |  23 | 5       |
+----+-----------+-----+-----+---------+
10 rows in set (0.00 sec)

t_song

mysql> select * from t_song;
+----+-----------------+
| id | song_name       |
+----+-----------------+
|  1 | 一生中最爱      |
|  2 | 沉默是金        |
|  3 | 笨小孩          |
|  4 | 我只在乎你      |
|  5 | 遥远的她        |
+----+-----------------+
5 rows in set (0.00 sec)

1.2 交叉连接

交叉连接的语法格式如下:

SELECT <字段名> FROM <表1> CROSS JOIN <表2> [WHERE子句]; # 推荐使用
或
SELECT <字段名> FROM <表1>, <表2> [WHERE子句];
语法说明如下:
字段名:需要查询的字段名称。
<表1><表2>:需要交叉连接的表名。
WHERE 子句:用来设置交叉连接的查询条件。

列1:使用 CROSS JOIN 查询出两张表中的笛卡尔积

mysql> SELECT * FROM t_super CROSS JOIN t_song;
+----+-----------+-----+-----+---------+----+-----------------+
| id | name      | sex | age | song_id | id | song_name       |
+----+-----------+-----+-----+---------+----+-----------------+
|  1 | 谭咏麟    | 男  |  25 | 1       |  1 | 一生中最爱      |
|  1 | 谭咏麟    | 男  |  25 | 1       |  2 | 沉默是金        |
|  1 | 谭咏麟    | 男  |  25 | 1       |  3 | 笨小孩          |
|  1 | 谭咏麟    | 男  |  25 | 1       |  4 | 我只在乎你      |
|  1 | 谭咏麟    | 男  |  25 | 1       |  5 | 遥远的她        |
|  2 | 张国荣    | 男  |  23 | 2       |  1 | 一生中最爱      |
|  2 | 张国荣    | 男  |  23 | 2       |  2 | 沉默是金        |
|  2 | 张国荣    | 男  |  23 | 2       |  3 | 笨小孩          |
|  2 | 张国荣    | 男  |  23 | 2       |  4 | 我只在乎你      |
|  2 | 张国荣    | 男  |  23 | 2       |  5 | 遥远的她        |
|  3 | 林青霞    | 女  |  23 | 1       |  1 | 一生中最爱      |
|  3 | 林青霞    | 女  |  23 | 1       |  2 | 沉默是金        |
|  3 | 林青霞    | 女  |  23 | 1       |  3 | 笨小孩          |
|  3 | 林青霞    | 女  |  23 | 1       |  4 | 我只在乎你      |
|  3 | 林青霞    | 女  |  23 | 1       |  5 | 遥远的她        |
|  4 | 刘德华    | 男  |  22 | 3       |  1 | 一生中最爱      |
|  4 | 刘德华    | 男  |  22 | 3       |  2 | 沉默是金        |
|  4 | 刘德华    | 男  |  22 | 3       |  3 | 笨小孩          |
|  4 | 刘德华    | 男  |  22 | 3       |  4 | 我只在乎你      |
|  4 | 刘德华    | 男  |  22 | 3       |  5 | 遥远的她        |
|  5 | 张曼玉    | 女  |  24 | 2       |  1 | 一生中最爱      |
|  5 | 张曼玉    | 女  |  24 | 2       |  2 | 沉默是金        |
|  5 | 张曼玉    | 女  |  24 | 2       |  3 | 笨小孩          |
|  5 | 张曼玉    | 女  |  24 | 2       |  4 | 我只在乎你      |
|  5 | 张曼玉    | 女  |  24 | 2       |  5 | 遥远的她        |
|  6 | 邓丽君    | 女  |  21 | 4       |  1 | 一生中最爱      |
|  6 | 邓丽君    | 女  |  21 | 4       |  2 | 沉默是金        |
|  6 | 邓丽君    | 女  |  21 | 4       |  3 | 笨小孩          |
|  6 | 邓丽君    | 女  |  21 | 4       |  4 | 我只在乎你      |
|  6 | 邓丽君    | 女  |  21 | 4       |  5 | 遥远的她        |
|  7 | 张学友    | 男  |  22 | 4       |  1 | 一生中最爱      |
|  7 | 张学友    | 男  |  22 | 4       |  2 | 沉默是金        |
|  7 | 张学友    | 男  |  22 | 4       |  3 | 笨小孩          |
|  7 | 张学友    | 男  |  22 | 4       |  4 | 我只在乎你      |
|  7 | 张学友    | 男  |  22 | 4       |  5 | 遥远的她        |
|  8 | 黎明      | 男  |  23 | 5       |  1 | 一生中最爱      |
|  8 | 黎明      | 男  |  23 | 5       |  2 | 沉默是金        |
|  8 | 黎明      | 男  |  23 | 5       |  3 | 笨小孩          |
|  8 | 黎明      | 男  |  23 | 5       |  4 | 我只在乎你      |
|  8 | 黎明      | 男  |  23 | 5       |  5 | 遥远的她        |
|  9 | 梅艳芳    | 女  |  22 | 5       |  1 | 一生中最爱      |
|  9 | 梅艳芳    | 女  |  22 | 5       |  2 | 沉默是金        |
|  9 | 梅艳芳    | 女  |  22 | 5       |  3 | 笨小孩          |
|  9 | 梅艳芳    | 女  |  22 | 5       |  4 | 我只在乎你      |
|  9 | 梅艳芳    | 女  |  22 | 5       |  5 | 遥远的她        |
| 10 | 陈慧娴    | 女  |  23 | 5       |  1 | 一生中最爱      |
| 10 | 陈慧娴    | 女  |  23 | 5       |  2 | 沉默是金        |
| 10 | 陈慧娴    | 女  |  23 | 5       |  3 | 笨小孩          |
| 10 | 陈慧娴    | 女  |  23 | 5       |  4 | 我只在乎你      |
| 10 | 陈慧娴    | 女  |  23 | 5       |  5 | 遥远的她        |
+----+-----------+-----+-----+---------+----+-----------------+
50 rows in set (0.00 sec)

笛卡尔积存在的问题:
笛卡尔积中容易存在大量的不合理数据,简单来说就是容易导致查询结果重复、混乱。

返回了 50 条记录,可以想象,当表中的数据较多时,得到的运行结果会非常长,而且得到的运行结果也没太大的意义。所以,通过交叉连接的方式进行多表查询的这种方法并不常用,我们应该尽量避免这种查询。

列2: 查询 song_name 表中的 id 字段和 t_super 表中的 song_id 字段相等的内容

mysql> SELECT * FROM t_song CROSS JOIN t_super  WHERE t_super.song_id = t_song.id;
+----+-----------------+----+-----------+-----+-----+---------+
| id | song_name       | id | name      | sex | age | song_id |
+----+-----------------+----+-----------+-----+-----+---------+
|  1 | 一生中最爱      |  1 | 谭咏麟    | 男  |  25 | 1       |
|  2 | 沉默是金        |  2 | 张国荣    | 男  |  23 | 2       |
|  1 | 一生中最爱      |  3 | 林青霞    | 女  |  23 | 1       |
|  3 | 笨小孩          |  4 | 刘德华    | 男  |  22 | 3       |
|  2 | 沉默是金        |  5 | 张曼玉    | 女  |  24 | 2       |
|  4 | 我只在乎你      |  6 | 邓丽君    | 女  |  21 | 4       |
|  4 | 我只在乎你      |  7 | 张学友    | 男  |  22 | 4       |
|  5 | 遥远的她        |  8 | 黎明      | 男  |  23 | 5       |
|  5 | 遥远的她        |  9 | 梅艳芳    | 女  |  22 | 5       |
|  5 | 遥远的她        | 10 | 陈慧娴    | 女  |  23 | 5       |
+----+-----------------+----+-----------+-----+-----+---------+
10 rows in set (0.01 sec)

如果在交叉连接时使用 WHERE 子句,MySQL 会先生成两个表的笛卡尔积,然后再选择满足 WHERE 条件的记录。因此,表的数量较多时,交叉连接会非常非常慢。一般情况下不建议使用交叉连接。–

在 MySQL 中,多表查询一般使用内连接和外连接,它们的效率要高于交叉连接。

2. 内连接

SELECT <字段名> FROM <表1> INNER JOIN <表2> [ON子句];
语法说明如下。
字段名:需要查询的字段名称。
<表1><表2>:需要内连接的表名。
INNER JOIN :内连接中可以省略 INNER 关键字,只用关键字 JOIN。
ON 子句:用来设置内连接的连接条件。

例 1
在 t_super 表和 t_song 表之间,使用内连接查询靓仔、靓女的姓名和相对应的歌曲名称

mysql> SELECT s.name,c.song_name FROM t_super s INNER JOIN  t_song c ON s.song_id = c.id;
+-----------+-----------------+
| name      | song_name       |
+-----------+-----------------+
| 谭咏麟    | 一生中最爱      |
| 张国荣    | 沉默是金        |
| 林青霞    | 一生中最爱      |
| 刘德华    | 笨小孩          |
| 张曼玉    | 沉默是金        |
| 邓丽君    | 我只在乎你      |
| 张学友    | 我只在乎你      |
| 黎明      | 遥远的她        |
| 梅艳芳    | 遥远的她        |
| 陈慧娴    | 遥远的她        |
+-----------+-----------------+
10 rows in set (0.00 sec)

注意: 我在上面查询的时候使用到了别名

当对多个表进行查询时,要在 SELECT 语句后面指定字段是来源于哪一张表。因此,在多表查询时,SELECT 语句后面的写法是表名.列名。另外,如果表名非常长的话,也可以给表设置别名,这样就可以直接在 SELECT 语句后面写上表的别名.列名。

3.外连接

外连接可以分为左外连接和右外连接2种,下面根据实例分别介绍左外连接和右外连接。

3.1 左连接

左外连接又称为左连接,使用 LEFT OUTER JOIN 关键字连接两个表,并使用 ON 子句来设置连接条件。

左连接的语法格式如下:

SELECT <字段名> FROM <表1> LEFT OUTER JOIN <表2> <ON子句>;
语法说明如下:
- 字段名:需要查询的字段名称。
- <表1><表2>:需要左连接的表名。
- LEFT OUTER JOIN:左连接中可以省略 OUTER 关键字,只使用关键字 LEFT JOIN。
- ON 子句:用来设置左连接的连接条件,不能省略。

t_song 表

mysql> select * from t_song;
+----+-----------------+
| id | song_name       |
+----+-----------------+
|  1 | 一生中最爱      |
|  2 | 沉默是金        |
|  3 | 笨小孩          |
|  4 | 我只在乎你      |
|  5 | 遥远的她        |
|  6 | NULL            |
+----+-----------------+
6 rows in set (0.00 sec)

t_super 表

mysql> select * from t_super;
+----+-----------+-----+-----+---------+
| id | name      | sex | age | song_id |
+----+-----------+-----+-----+---------+
|  1 | 谭咏麟    | 男  |  25 | 1       |
|  2 | 张国荣    | 男  |  23 | 2       |
|  3 | 林青霞    | 女  |  23 | 1       |
|  4 | 刘德华    | 男  |  22 | 3       |
|  5 | 张曼玉    | 女  |  24 | 2       |
|  6 | 邓丽君    | 女  |  21 | 4       |
|  7 | 张学友    | 男  |  22 | 4       |
|  8 | 黎明      | 男  |  23 | 5       |
|  9 | 梅艳芳    | 女  |  22 | 5       |
| 10 | 陈慧娴    | 女  |  23 | 5       |
| 11 | 陈百强    | 男  |  22 | 7       |
+----+-----------+-----+-----+---------+
11 rows in set (0.00 sec)

在t_super 表和 t_song表中查询所有学生姓名和相对应的课程名称,包括没有课程的学生, SQL 语句和运行结果如下:

mysql> SELECT s.name,c.song_name FROM t_super  s LEFT OUTER JOIN t_song c ON s.song_id=c.id;
+-----------+-----------------+
| name      | song_name       |
+-----------+-----------------+
| 谭咏麟    | 一生中最爱      |
| 张国荣    | 沉默是金        |
| 林青霞    | 一生中最爱      |
| 刘德华    | 笨小孩          |
| 张曼玉    | 沉默是金        |
| 邓丽君    | 我只在乎你      |
| 张学友    | 我只在乎你      |
| 黎明      | 遥远的她        |
| 梅艳芳    | 遥远的她        |
| 陈慧娴    | 遥远的她        |
| 陈百强    | NULL            |
+-----------+-----------------+
11 rows in set (0.00 sec)

可以看到,运行结果显示了 11 条记录,name 为 陈百强 的靓仔目前没有歌曲,因为对应的 t_song表中没有该陈百强的歌曲信息,所以该条记录只取出了 t_super 表中相应的值,而从 t_song 表中取出的值为 NULL。

3.2右连接

右外连接又称为右连接,右连接是左连接的反向连接。使用 RIGHT OUTER JOIN 关键字连接两个表,并使用 ON 子句来设置连接条件。

右连接的语法格式如下:

SELECT <字段名> FROM <表1> RIGHT OUTER JOIN <表2> <ON子句>;

语法说明如下:
- 字段名:需要查询的字段名称。
- <表1><表2>:需要右连接的表名。
- RIGHT OUTER JOIN:右连接中可以省略 OUTER 关键字,只使用关键字 RIGHT JOIN。
- ON 子句:用来设置右连接的连接条件,不能省略。

例 2
在 t_super表和 t_song表中查询所有课程,包括没有学生的课程,SQL 语句和运行结果如下:

mysql> SELECT s.name,c.song_name FROM t_super s RIGHT OUTER JOIN t_song c ON s.song_id=c.id;
+-----------+-----------------+
| name      | song_name       |
+-----------+-----------------+
| 谭咏麟    | 一生中最爱      |
| 张国荣    | 沉默是金        |
| 林青霞    | 一生中最爱      |
| 刘德华    | 笨小孩          |
| 张曼玉    | 沉默是金        |
| 邓丽君    | 我只在乎你      |
| 张学友    | 我只在乎你      |
| 黎明      | 遥远的她        |
| 梅艳芳    | 遥远的她        |
| 陈慧娴    | 遥远的她        |
| NULL      | NULL            |
+-----------+-----------------+
11 rows in set (0.00 sec)

可以看到,结果显示了 11 条记录,名称为 HTML 的课程目前没有学生,因为对应的t_super表中并没有该学生的信息,所以该条记录只取出了 t_song表中相应的值,而从 t_super表中取出的值为 NULL。

多个表左/右连接时,在 ON 子句后连续使用 LEFT/RIGHT OUTER JOIN 或 LEFT/RIGHT JOIN 即可。

使用外连接查询时,一定要分清需要查询的结果,是需要显示左表的全部记录还是右表的全部记录,然后选择相应的左连接和右连接。

2. 分组查询

在 MySQL 中,GROUP BY 关键字可以根据一个或多个字段对查询结果进行分组。

使用 GROUP BY 关键字的语法格式如下:

GROUP BY  <字段名>

其中,字段名表示需要分组的字段名称,多个字段时用逗号隔开。

2.1 GROUP BY 与 GROUP_CONCAT()

GROUP BY 关键字可以和 GROUP_CONCAT() 函数一起使用。GROUP_CONCAT() 函数会把每个分组的字段值都显示出来。

下面根据 t_super表中的 sex 字段进行分组查询,使用 GROUP_CONCAT() 函数将每个分组的 name 字段的值都显示出来。SQL 语句和运行结果如下:

mysql>  SELECT `sex`, GROUP_CONCAT(name) FROM t_super GROUP BY sex;                     +-----+----------------------------------------------------------+
| sex | GROUP_CONCAT(name)                                       |
+-----+----------------------------------------------------------+
| 女  | 林青霞,张曼玉,邓丽君,梅艳芳,陈慧娴                            |
| 男  | 谭咏麟,张国荣,刘德华,张学友,黎明,陈百强                        |
+-----+----------------------------------------------------------+
2 rows in set (0.00 sec)

由结果可以看到,查询结果分为两组,sex 字段值为"女"的是一组,值为"男"的是一组,且每组的学生姓名都显示出来了。

下面根据 tb_students_info 表中的 age 和 sex 字段进行分组查询。SQL 语句和运行结果如下:

mysql> mysql> SELECT age,sex,GROUP_CONCAT(name) FROM t_super  GROUP BY age,sex;
+-----+-----+-------------------------------+
| age | sex | GROUP_CONCAT(name)            |
+-----+-----+-------------------------------+
|  21 | 女  | 邓丽君                        |
|  22 | 女  | 梅艳芳                        |
|  22 | 男  | 刘德华,张学友,陈百强          |
|  23 | 女  | 林青霞,陈慧娴                 |
|  23 | 男  | 张国荣,黎明                   |
|  24 | 女  | 张曼玉                        |
|  25 | 男  | 谭咏麟                        |
+-----+-----+-------------------------------+
7 rows in set (0.00 sec)

上面实例在分组过程中,先按照 age 字段进行分组,当 age 字段值相等时,再把 age 字段值相等的记录按照 sex 字段进行分组。

多个字段分组查询时,会先按照第一个字段进行分组。如果第一个字段中有相同的值,MySQL 才会按照第二个字段进行分组。如果第一个字段中的数据都是唯一的,那么 MySQL 将不再对第二个字段进行分组

2.2 GROUP BY 与聚合函数

在数据统计时,GROUP BY 关键字经常和聚合函数一起使用。

聚合函数包括 COUNT(),SUM(),AVG(),MAX() 和 MIN()。其中,COUNT() 用来统计记录的条数;SUM() 用来计算字段值的总和;AVG() 用来计算字段值的平均值;MAX() 用来查询字段的最大值;MIN() 用来查询字段的最小值。

下面根据 tb_students_info 表的 sex 字段进行分组查询,使用 COUNT() 函数计算每一组的记录数。SQL 语句和运行结果如下:

mysql>  SELECT sex,COUNT(sex) FROM t_super GROUP BY sex;
+-----+------------+
| sex | COUNT(sex) | # 觉得这个太长了用别名
+-----+------------+
| 女  |          5 |
| 男  |          6 |
+-----+------------+
2 rows in set (0.00 sec)

结果显示,sex 字段值为"女"的记录是一组,有 5 条记录;sex 字段值为"男"的记录是一组,有 5 条记录。

2.3 GROUP BY 与 WITH ROLLUP

WITH POLLUP 关键字用来在所有记录的最后加上一条记录,这条记录是上面所有记录的总和,即统计记录数量。

下面根据 tb_students_info 表中的 sex 字段进行分组查询,并使用 WITH ROLLUP 显示记录的总和:

mysql> mysql> SELECT sex,GROUP_CONCAT(name) FROM t_super GROUP BY sex WITH ROLLUP;
+---------------------------------------------------------------------------+
| sex | GROUP_CONCAT(name)                                                  |
+-----+---------------------------------------------------------------------+
| 女  | 林青霞,张曼玉,邓丽君,梅艳芳,陈慧娴                                        |
| 男  | 谭咏麟,张国荣,刘德华,张学友,黎明,陈百强                                   |
| NULL | 林青霞,张曼玉,邓丽君,梅艳芳,陈慧娴,谭咏麟,张国荣,刘德华,张学友,黎明,陈百强    |
+-----+----------------------------------------------------------------------+

查询结果显示,GROUP_CONCAT(name) 显示了每个分组的 name 字段值。同时,最后一条记录的 GROUP_CONCAT(name) 字段的值刚好是上面分组 name 字段值的总和。

3. 子查询

子查询在 WHERE 中的语法格式如下:

WHERE <表达式> <操作符> (子查询)

例 1
使用子查询在 t_super表和 t_song表中查询学习 一生中最爱 课程的学生姓名,SQL 语句和运行结果如下:

mysql> SELECT name FROM t_super WHERE song_id IN (SELECT id FROM t_song WHERE song_name = '一生中最爱');
+-----------+
| name      |
+-----------+
| 谭咏麟    |
| 林青霞    |
+-----------+
2 rows in set (0.00 sec)

结果显示,学习一生中最爱 课程的只有 谭咏麟 和 林青霞。上述查询过程也可以分为以下 2 步执行,实现效果是相同的。
首先单独执行内查询,查询出 t_song 表中课程为 一生中最爱 的 id,SQL 语句和运行结果如下:

mysql> SELECT id FROM t_song WHERE song_name = '一生中最爱';
+----+
| id |
+----+
|  1 |
+----+
1 row in set (0.00 sec)

可以看到,符合条件的 id 字段的值为 1。
然后执行外层查询,在 t_super 表中查询 song_id 等于 1 的学生姓名。SQL 语句和运行结果如下:

mysql> SELECT name FROM t_super  WHERE song_id IN (1);
+-----------+
| name      |
+-----------+
| 谭咏麟    |
| 林青霞    |
+-----------+
2 rows in set (0.00 sec)

习惯上,外层的 SELECT 查询称为父查询,圆括号中嵌入的查询称为子查询(子查询必须放在圆括号内)。MySQL 在处理上例的 SELECT 语句时,执行流程为:先执行子查询,再执行父查询。

例 2
与例 1 类似,在 SELECT 语句中使用 NOT IN 关键字,查询没有学习 一生中最爱 课程的学生姓名,SQL 语句和运行结果如下:

mysql> SELECT name FROM t_super WHERE song_id NOT IN (SELECT id FROM t_song WHERE song_name = '一生中最爱');
+-----------+
| name      |
+-----------+
| 张国荣    |
| 刘德华    |
| 张曼玉    |
| 邓丽君    |
| 张学友    |
| 黎明      |
| 梅艳芳    |
| 陈慧娴    |
| 陈百强    |
+-----------+
9 rows in set (0.00 sec)

可以看出,运行结果与上面的例子刚好相反,没有学习 一生中最爱 课程的是除了 谭咏麟 和 林青霞 之外的学生。
例 3
使用=运算符,在 t_song 表和 t_super 表中查询出所有学习 我只在乎你 课程的学生姓名,SQL 语句和运行结果如下:

mysql> SELECT name FROM t_super WHERE song_id = (SELECT id FROM t_song WHERE song_name = '我只在乎你');
+-----------+
| name      |
+-----------+
| 邓丽君    |
| 张学友    |
+-----------+
2 rows in set (0.00 sec)

结果显示,学习 我只在乎你 课程的学生只有 邓丽君和 张学友。

例 4
使用<>运算符,在 t_song 表和 t_super 表中查询出没有学习 我只在乎你 课程的学生姓名,SQL 语句和运行结果如下:

mysql> SELECT name FROM t_super  WHERE song_id <> (SELECT id FROM t_song WHERE song_name = '我只在乎你');
+-----------+
| name      |
+-----------+
| 谭咏麟    |
| 张国荣    |
| 林青霞    |
| 刘德华    |
| 张曼玉    |
| 黎明      |
| 梅艳芳    |
| 陈慧娴    |
| 陈百强    |
+-----------+
9 rows in set (0.01 sec)

可以看出,运行结果与例 3 刚好相反,没有学习 我只在乎你 课程的是除了 邓丽君 和 张学友 之外的学生。

例 5
查询 t_song 表中是否存在 id=1 的课程,如果存在,就查询出 t_super 表中的记录,SQL 语句和运行结果如下:

mysql> SELECT * FROM t_super WHERE EXISTS(SELECT song_name FROM t_song WHERE id=1);
+----+-----------+-----+-----+---------+
| id | name      | sex | age | song_id |
+----+-----------+-----+-----+---------+
|  1 | 谭咏麟    | 男  |  25 | 1       |
|  2 | 张国荣    | 男  |  23 | 2       |
|  3 | 林青霞    | 女  |  23 | 1       |
|  4 | 刘德华    | 男  |  22 | 3       |
|  5 | 张曼玉    | 女  |  24 | 2       |
|  6 | 邓丽君    | 女  |  21 | 4       |
|  7 | 张学友    | 男  |  22 | 4       |
|  8 | 黎明      | 男  |  23 | 5       |
|  9 | 梅艳芳    | 女  |  22 | 5       |
| 10 | 陈慧娴    | 女  |  23 | 5       |
| 11 | 陈百强    | 男  |  22 | 7       |
+----+-----------+-----+-----+---------+
11 rows in set (0.00 sec)

由结果可以看到,t_song 表中存在 id=1 的记录,因此 EXISTS 表达式返回 TRUE,外层查询语句接收 TRUE 之后对表 t_super 进行查询,返回所有的记录。

EXISTS 关键字可以和其它查询条件一起使用,条件表达式与 EXISTS 关键字之间用 AND 和 OR 连接。

例 6
查询 t_song 表中是否存在 id=1 的课程,如果存在,就查询出 t_super 表中 age 字段大于 24 的记录,SQL 语句和运行结果如下:

mysql> SELECT * FROM t_super WHERE age>24 AND EXISTS(SELECT song_name FROM t_song WHERE id=1);
+----+-----------+-----+-----+---------+
| id | name      | sex | age | song_id |
+----+-----------+-----+-----+---------+
|  1 | 谭咏麟    | 男  |  25 | 1       |
+----+-----------+-----+-----+---------+
1 row in set (0.00 sec)

结果显示,从 t_super 表中查询出了一条记录,这条记录的 age 字段取值为 25。内层查询语句从 t_song 表中查询到记录,返回 TRUE。外层查询语句开始进行查询。根据查询条件,从 t_super 表中查询 age 大于 24 的记录。

子查询的功能也可以通过表连接完成,但是子查询会使 SQL 语句更容易阅读和编写。

一般来说,表连接(内连接和外连接等)都可以用子查询替换,但反过来却不一定,有的子查询不能用表连接来替换。子查询比较灵活、方便、形式多样,适合作为查询的筛选条件,而表连接更适合于查看连接表的数据。

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值