• 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)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    t_song

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

    1.2 交叉连接

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

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

    列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)
    
    • 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
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56

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

    返回了 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)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

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

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

    2. 内连接

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

    例 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)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

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

    当对多个表进行查询时,要在 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 子句:用来设置左连接的连接条件,不能省略。
    • 1
    • 2
    • 3
    • 4
    • 5

    t_song 表

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

    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)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    在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)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    可以看到,运行结果显示了 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 子句:用来设置右连接的连接条件,不能省略。
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    例 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)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    可以看到,结果显示了 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)
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7

      由结果可以看到,查询结果分为两组,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)
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12

      上面实例在分组过程中,先按照 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)
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7

      结果显示,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 | 林青霞,张曼玉,邓丽君,梅艳芳,陈慧娴,谭咏麟,张国荣,刘德华,张学友,黎明,陈百强    |
      +-----+----------------------------------------------------------------------+
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7

      查询结果显示,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)
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7

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

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

        可以看到,符合条件的 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)
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7

        习惯上,外层的 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)
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14

        可以看出,运行结果与上面的例子刚好相反,没有学习 一生中最爱 课程的是除了 谭咏麟 和 林青霞 之外的学生。
        例 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)
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7

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

        例 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)
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14

        可以看出,运行结果与例 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)
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16

        由结果可以看到,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)
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6

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

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

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

      • 相关阅读:
        工厂模式,装饰模式(新手)
        Django笔记三十五之admin后台界面介绍
        Redis详解(一)
        第七章:命令行操作基础
        Markdown使用模板
        python自学入门(打卡五)2022-10-29
        如何快速部署Apache服务器并使用内网穿透实现远程连接
        【win32_000】视频截图
        java街边熟食店卤菜网上商城系统springboot+vue
        CISSP考试回忆录 | 考试契机、曲折备考、考试现场回顾
      • 原文地址:https://blog.csdn.net/m0_58805648/article/details/125533162