日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

MySQL的多表查询

發布時間:2023/12/14 数据库 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 MySQL的多表查询 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

    • MySQL的多表查詢
      • 什么是多表聯合查詢
      • 交叉連接(CROSS JOIN)
        • 笛卡爾積
        • 交叉連接
      • 內連接
      • 外連接
        • 左連接
        • 右連接
      • 分組查詢
        • GROUP BY單獨使用
        • GROUP BY 與 GROUP_CONCAT()
        • GROUP BY 與聚合函數
        • GROUP BY 與 WITH ROLLUP
      • 子查詢

MySQL的多表查詢

什么是多表聯合查詢

多表查詢就是同時查詢兩個或兩個以上的表。

在 MySQL 中,多表查詢主要有交叉連接、內連接、外連接、分組查詢與子查詢等5種。

交叉連接(CROSS JOIN)

笛卡爾積

交叉連接(CROSS JOIN):有兩種,顯式的和隱式的2種,一般用來返回連接表的笛卡爾積。

笛卡爾積(Cartesian product)是指兩個集合 X 和 Y 的乘積。

例如,有 A 和 B 兩個集合,它們的值如下:

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

集合 A×B 和 B×A 的結果集分別表示為:

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

以上 A×B 和 B×A 的結果就叫做兩個集合的笛卡爾積。

并且,從以上結果我們可以看出:

  • 兩個集合相乘,不滿足交換率,即 A×B≠B×A。
  • A 集合和 B 集合的笛卡爾積是 A 集合的元素個數 × B 集合的元素個數。

多表查詢遵循的算法就是以上提到的笛卡爾積,表與表之間的連接可以看成是在做乘法運算。

在實際應用中,應避免使用笛卡爾積,因為笛卡爾積中容易存在大量的不合理數據,簡單來說就是容易導致查詢結果重復、混亂。

交叉連接

交叉連接的語法格式如下:

SELECT <字段名> FROM <表1> CROSS JOIN <表2> [WHERE子句];

SELECT <字段名> FROM <表1>, <表2> [WHERE子句];

語法說明如下:

  • 字段名:需要查詢的字段名稱。
  • <表1><表2>:需要交叉連接的表名。
  • WHERE 子句:用來設置交叉連接的查詢條件。

注意:多個表交叉連接時,在 FROM 后連續使用 CROSS JOIN 或,即可。以上兩種語法的返回結果是相同的,但是第一種語法才是官方建議的標準寫法。

交叉連接可以查詢兩個或兩個以上的表,為了更好的理解,我們就講解兩個表的交叉連接查詢。

例 1

查詢學生信息表和科目信息表,并得到一個笛卡爾積。

為了方便觀察學生信息表和科目表交叉連接后的運行結果,我們先分別查詢出這兩個表的數據,再進行交叉連接查詢。

1)查詢 tb_students_info 表中的數據,SQL 語句和運行結果如下:

mysql> create database school; Query OK, 1 row affected (0.01 sec)mysql> use school; Database changed mysql> create table tb_students_info(id int not null primary key auto_increment,name varchar(30),age tinyint,sex varchar(6),height int,course_id int); Query OK, 0 rows affected (0.01 sec)mysql> desc tb_students_info; +-----------+-------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-----------+-------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | name | varchar(30) | YES | | NULL | | | age | tinyint(4) | YES | | NULL | | | sex | varchar(6) | YES | | NULL | | | height | int(11) | YES | | NULL | | | course_id | int(11) | YES | | NULL | | +-----------+-------------+------+-----+---------+----------------+ 6 rows in set (0.01 sec) mysql> insert tb_students_info(name,age,sex,height,course_id) values('tom',22,'male',172,1),('mary',25,'female',170,4),('lily',23,'male',170,2),('jim',26,'male',176,1),('henry',24,'male',180,3),('sean',39,'male',178,3),('lisi',25,'female',176,2),('lisa',24,'male',181,2),('green',22,'female',188,1),('jerry',29,'male',175,3); Query OK, 10 rows affected (0.00 sec) Records: 10 Duplicates: 0 Warnings: 0mysql> SELECT * FROM tb_students_info; +----+-------+------+--------+--------+-----------+ | id | name | age | sex | height | course_id | +----+-------+------+--------+--------+-----------+ | 1 | tom | 22 | male | 172 | 1 | | 2 | mary | 25 | female | 170 | 4 | | 3 | lily | 23 | male | 170 | 2 | | 4 | jim | 26 | male | 176 | 1 | | 5 | henry | 24 | male | 180 | 3 | | 6 | sean | 39 | male | 178 | 3 | | 7 | lisi | 25 | female | 176 | 2 | | 8 | lisa | 24 | male | 181 | 2 | | 9 | green | 22 | female | 188 | 1 | | 10 | jerry | 29 | male | 175 | 3 | +----+-------+------+--------+--------+-----------+ 10 rows in set (0.00 sec)

2)查詢 tb_course 表中的數據,SQL 語句和運行結果如下:

mysql> create table tb_course(id int not null primary key auto_increment,course_name varchar(30));Query OK, 0 rows affected (0.07 sec)mysql> desc tb_course; +-------------+-------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------------+-------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | course_name | varchar(30) | YES | | NULL | | +-------------+-------------+------+-----+---------+----------------+ 2 rows in set (0.00 sec)mysql> insert tb_course(course_name) values('Java'),('MySQL'),('Python'),('Go'),('C++'); Query OK, 5 rows affected (0.00 sec) Records: 5 Duplicates: 0 Warnings: 0mysql> SELECT * FROM tb_course; +----+-------------+ | id | course_name | +----+-------------+ | 1 | Java | | 2 | MySQL | | 3 | Python | | 4 | Go | | 5 | C++ | +----+-------------+ 5 rows in set (0.00 sec)

3)使用 CROSS JOIN 查詢出兩張表中的笛卡爾積,SQL 語句和運行結果如下:

mysql> SELECT * FROM tb_course CROSS JOIN tb_students_info; +----+-------------+----+-------+------+--------+--------+-----------+ | id | course_name | id | name | age | sex | height | course_id | +----+-------------+----+-------+------+--------+--------+-----------+ | 1 | Java | 1 | tom | 22 | male | 172 | 1 | | 2 | MySQL | 1 | tom | 22 | male | 172 | 1 | | 3 | Python | 1 | tom | 22 | male | 172 | 1 | | 4 | Go | 1 | tom | 22 | male | 172 | 1 | | 5 | C++ | 1 | tom | 22 | male | 172 | 1 | | 1 | Java | 2 | mary | 25 | female | 170 | 4 | | 2 | MySQL | 2 | mary | 25 | female | 170 | 4 | | 3 | Python | 2 | mary | 25 | female | 170 | 4 | | 4 | Go | 2 | mary | 25 | female | 170 | 4 | | 5 | C++ | 2 | mary | 25 | female | 170 | 4 | | 1 | Java | 3 | lily | 23 | male | 170 | 2 | | 2 | MySQL | 3 | lily | 23 | male | 170 | 2 | | 3 | Python | 3 | lily | 23 | male | 170 | 2 | | 4 | Go | 3 | lily | 23 | male | 170 | 2 | | 5 | C++ | 3 | lily | 23 | male | 170 | 2 | | 1 | Java | 4 | jim | 26 | male | 176 | 1 | | 2 | MySQL | 4 | jim | 26 | male | 176 | 1 | | 3 | Python | 4 | jim | 26 | male | 176 | 1 | | 4 | Go | 4 | jim | 26 | male | 176 | 1 | | 5 | C++ | 4 | jim | 26 | male | 176 | 1 | | 1 | Java | 5 | henry | 24 | male | 180 | 3 | | 2 | MySQL | 5 | henry | 24 | male | 180 | 3 | | 3 | Python | 5 | henry | 24 | male | 180 | 3 | | 4 | Go | 5 | henry | 24 | male | 180 | 3 | | 5 | C++ | 5 | henry | 24 | male | 180 | 3 | | 1 | Java | 6 | sean | 39 | male | 178 | 3 | | 2 | MySQL | 6 | sean | 39 | male | 178 | 3 | | 3 | Python | 6 | sean | 39 | male | 178 | 3 | | 4 | Go | 6 | sean | 39 | male | 178 | 3 | | 5 | C++ | 6 | sean | 39 | male | 178 | 3 | | 1 | Java | 7 | lisi | 25 | female | 176 | 2 | | 2 | MySQL | 7 | lisi | 25 | female | 176 | 2 | | 3 | Python | 7 | lisi | 25 | female | 176 | 2 | | 4 | Go | 7 | lisi | 25 | female | 176 | 2 | | 5 | C++ | 7 | lisi | 25 | female | 176 | 2 | | 1 | Java | 8 | lisa | 24 | male | 181 | 2 | | 2 | MySQL | 8 | lisa | 24 | male | 181 | 2 | | 3 | Python | 8 | lisa | 24 | male | 181 | 2 | | 4 | Go | 8 | lisa | 24 | male | 181 | 2 | | 5 | C++ | 8 | lisa | 24 | male | 181 | 2 | | 1 | Java | 9 | green | 22 | female | 188 | 1 | | 2 | MySQL | 9 | green | 22 | female | 188 | 1 | | 3 | Python | 9 | green | 22 | female | 188 | 1 | | 4 | Go | 9 | green | 22 | female | 188 | 1 | | 5 | C++ | 9 | green | 22 | female | 188 | 1 | | 1 | Java | 10 | jerry | 29 | male | 175 | 3 | | 2 | MySQL | 10 | jerry | 29 | male | 175 | 3 | | 3 | Python | 10 | jerry | 29 | male | 175 | 3 | | 4 | Go | 10 | jerry | 29 | male | 175 | 3 | | 5 | C++ | 10 | jerry | 29 | male | 175 | 3 | +----+-------------+----+-------+------+--------+--------+-----------+ 50 rows in set (0.00 sec)

由運行結果可以看出,兩張表交叉連接查詢后,返回了50 條記錄。可以想象,當表中的數據較多時,得到的運行結果會非常長,而且得到的運行結果也沒太大的意義。所以,通過交叉連接的方式進行多表查詢的這種方法并不常用,我們應該盡量避免這種查詢。

例 2

查詢 tb_course 表中的 id 字段和 tb_students_info 表中的 interst_name字段相等的內容, SQL 語句和運行結果如下:

mysql> SELECT * FROM tb_course CROSS JOIN tb_students_info WHERE tb_students_info.interst_id = tb_course.id; +----+--------------+----+-----------+------+--------+------------+ | id | interst_name | id | name | age | sex | interst_id | +----+--------------+----+-----------+------+--------+------------+ | 1 | sleep | 1 | tom | 22 | male | 1 | | 4 | ski | 2 | mary | 25 | female | 4 | | 2 | pubg | 3 | sean | 23 | male | 2 | | 1 | sleep | 4 | susan | 26 | male | 1 | | 3 | surf | 5 | qiuyi | 27 | female | 3 | | 3 | surf | 6 | jim | 24 | male | 3 | | 3 | surf | 7 | wangwu | 39 | male | 3 | | 2 | pubg | 8 | zhangshan | 25 | female | 2 | | 2 | pubg | 9 | lily | 24 | male | 2 | | 1 | sleep | 10 | lisa | 22 | female | 1 | +----+--------------+----+-----------+------+--------+------------+ 10 rows in set (0.00 sec)

如果在交叉連接時使用 WHERE 子句,MySQL 會先生成兩個表的笛卡爾積,然后再選擇滿足 WHERE 條件的記錄。因此,表的數量較多時,交叉連接會非常非常慢。一般情況下不建議使用交叉連接。

在 MySQL 中,多表查詢一般使用內連接和外連接,它們的效率要高于交叉連接。

內連接

內連接(INNER JOIN)主要通過設置連接條件的方式,來移除查詢結果中某些數據行的交叉連接。簡單來說,就是利用條件表達式來消除交叉連接的某些數據行。

內連接使用 INNER JOIN 關鍵字連接兩張表,并使用 ON 子句來設置連接條件。如果沒有連接條件,INNER JOIN 和 CROSS JOIN 在語法上是等同的,兩者可以互換。

內連接的語法格式如下:

SELECT <字段名> FROM <表1> INNER JOIN <表2> [ON子句];

語法說明如下。

  • 字段名:需要查詢的字段名稱。
  • <表1><表2>:需要內連接的表名。
  • INNER JOIN :內連接中可以省略 INNER 關鍵字,只用關鍵字 JOIN。
  • ON 子句:用來設置內連接的連接條件。

INNER JOIN 也可以使用 WHERE 子句指定連接條件,但是 INNER JOIN … ON 語法是官方的標準寫法,而且 WHERE 子句在某些時候會影響查詢的性能。

多個表內連接時,在 FROM 后連續使用 INNER JOIN 或 JOIN 即可。

內連接可以查詢兩個或兩個以上的表。為了更好的理解,暫時只講解兩個表的連接查詢。

例 1

在 tb_students_info 表和 tb_course 表之間,使用內連接查詢學生姓名和相對應的課程名稱,SQL 語句和運行結果如下。

mysql> SELECT s.name,c.course_name FROM tb_students_info s INNER JOIN tb_course c ON s.course_id = c.id; +-------+-------------+ | name | course_name | +-------+-------------+ | tom | Java | | mary | Go | | lily | MySQL | | jim | Java | | henry | Python | | sean | Python | | lisi | MySQL | | lisa | MySQL | | green | Java | | jerry | Python | +-------+-------------+ 10 rows in set (0.00 sec)

在這里的查詢語句中,兩個表之間的關系通過 INNER JOIN指定,連接的條件使用ON子句給出。

注意:當對多個表進行查詢時,要在 SELECT 語句后面指定字段是來源于哪一張表。因此,在多表查詢時,SELECT 語句后面的寫法是表名.列名。另外,如果表名非常長的話,也可以給表設置別名,這樣就可以直接在 SELECT 語句后面寫上表的別名.列名。

外連接

內連接的查詢結果都是符合連接條件的記錄,而外連接會先將連接的表分為基表和參考表,再以基表為依據返回滿足和不滿足條件的記錄。

外連接可以分為左外連接和右外連接2種,下面根據實例分別介紹左外連接和右外連接。

左連接

左外連接又稱為左連接,使用 LEFT OUTER JOIN 關鍵字連接兩個表,并使用 ON 子句來設置連接條件。

左連接的語法格式如下:

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

語法說明如下:

  • 字段名:需要查詢的字段名稱。
  • <表1><表2>:需要左連接的表名。
  • LEFT OUTER JOIN:左連接中可以省略 OUTER 關鍵字,只使用關鍵字 LEFT JOIN。
  • ON 子句:用來設置左連接的連接條件,不能省略。

上述語法中,"表1"為基表,"表2"為參考表。左連接查詢時,可以查詢出"表1"中的所有記錄和"表2"中匹配連接條件的記錄。如果"表1"的某行在"表2"中沒有匹配行,那么在返回結果中,"表2"的字段值均為空值(NULL)。

例 1

在進行左連接查詢之前,我們先查看 tb_course 和 tb_students_info 兩張表中的數據。SQL 語句和運行結果如下:

mysql> insert tb_students_info(name,age,sex,height,course_id) values('liming',22,'male',180,7); Query OK, 1 row affected (0.01 sec)mysql> insert tb_course(course_name) values('HTML'); Query OK, 1 row affected (0.01 sec)mysql> SELECT * FROM tb_students_info; +----+--------+------+--------+--------+-----------+ | id | name | age | sex | height | course_id | +----+--------+------+--------+--------+-----------+ | 1 | tom | 22 | male | 172 | 1 | | 2 | mary | 25 | female | 170 | 4 | | 3 | lily | 23 | male | 170 | 2 | | 4 | jim | 26 | male | 176 | 1 | | 5 | henry | 24 | male | 180 | 3 | | 6 | sean | 39 | male | 178 | 3 | | 7 | lisi | 25 | female | 176 | 2 | | 8 | lisa | 24 | male | 181 | 2 | | 9 | green | 22 | female | 188 | 1 | | 10 | jerry | 29 | male | 175 | 3 | | 11 | liming | 22 | male | 180 | 7 | +----+--------+------+--------+--------+-----------+ 11 rows in set (0.01 sec)mysql> SELECT * FROM tb_course; +----+-------------+ | id | course_name | +----+-------------+ | 1 | Java | | 2 | MySQL | | 3 | Python | | 4 | Go | | 5 | C++ | | 6 | HTML | +----+-------------+ 6 rows in set (0.00 sec)

在 tb_students_info 表和 tb_course 表中查詢所有學生姓名和相對應的課程名稱,包括沒有課程的學生,SQL 語句和運行結果如下:

mysql> SELECT s.name,c.course_name FROM tb_students_info s LEFT OUTER JOIN tb_course c ON s.`course_id`=c.`id`; +--------+-------------+ | name | course_name | +--------+-------------+ | tom | Java | | mary | Go | | lily | MySQL | | jim | Java | | henry | Python | | sean | Python | | lisi | MySQL | | lisa | MySQL | | green | Java | | jerry | Python | | liming | NULL | +--------+-------------+ 11 rows in set (0.00 sec)

所以該條記錄只取出了 tb_students_info 表中相應的值,而從 tb_course 表中取出的值為 NULL。

右連接

右外連接又稱為右連接,右連接是左連接的反向連接。使用 RIGHT OUTER JOIN 關鍵字連接兩個表,并使用 ON 子句來設置連接條件。

右連接的語法格式如下:

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

語法說明如下:

  • 字段名:需要查詢的字段名稱。
  • <表1><表2>:需要右連接的表名。
  • RIGHT OUTER JOIN:右連接中可以省略 OUTER 關鍵字,只使用關鍵字 RIGHT JOIN。
  • ON 子句:用來設置右連接的連接條件,不能省略。

與左連接相反,右連接以"表2"為基表,"表1"為參考表。右連接查詢時,可以查詢出"表2"中的所有記錄和"表1"中匹配連接條件的記錄。如果"表2"的某行在"表1"中沒有匹配行,那么在返回結果中,"表1"的字段值均為空值(NULL)。

例 2

在 tb_students_info 表和 tb_course 表中查詢所有課程,包括沒有學生的課程,SQL 語句和運行結果如下:

mysql> SELECT s.name,c.course_name FROM tb_students_info s RIGHT OUTER JOIN tb_course c ON s.`course_id`=c.`id`; +-------+-------------+ | name | course_name | +-------+-------------+ | tom | Java | | mary | Go | | lily | MySQL | | jim | Java | | henry | Python | | sean | Python | | lisi | MySQL | | lisa | MySQL | | green | Java | | jerry | Python | | NULL | C++ | +-------+-------------+ 11 rows in set (0.00 sec)

可以看到,結果顯示了 11 條記錄,名稱為 HTML 的課程目前沒有學生,因為對應的tb_students_info 表中并沒有該學生的信息,所以該條記錄只取出了 tb_course 表中相應的值,而從 tb_students_info 表中取出的值為 NULL。

多個表左/右連接時,在 ON 子句后連續使用 LEFT/RIGHT OUTER JOIN 或 LEFT/RIGHT JOIN 即可。

使用外連接查詢時,一定要分清需要查詢的結果,是需要顯示左表的全部記錄還是右表的全部記錄,然后選擇相應的左連接和右連接。

分組查詢

在 MySQL 中,GROUP BY 關鍵字可以根據一個或多個字段對查詢結果進行分組。

使用 GROUP BY 關鍵字的語法格式如下:

GROUP BY <字段名>

其中,"字段名"表示需要分組的字段名稱,多個字段時用逗號隔開。

GROUP BY單獨使用

單獨使用 GROUP BY 關鍵字時,查詢結果會只顯示每個分組的第一條記錄。

下面根據 tb_students_info 表中的 sex 字段進行分組查詢,SQL 語句和運行結果如下:

mysql> SELECT `name`,`sex` FROM tb_students_info GROUP BY sex; +------+--------+ | name | sex | +------+--------+ | mary | female | | tom | male | +------+--------+ 2 rows in set (0.01 sec)

結果中只顯示了兩條記錄,這兩條記錄的 sex 字段的值分別為“女”和“男”。

GROUP BY 與 GROUP_CONCAT()

GROUP BY 關鍵字可以和 GROUP_CONCAT() 函數一起使用。GROUP_CONCAT() 函數會把每個分組的字段值都顯示出來。

下面根據 tb_students_info 表中的 sex 字段進行分組查詢,使用 GROUP_CONCAT() 函數將每個分組的 name 字段的值都顯示出來。SQL 語句和運行結果如下:

mysql> SELECT `sex`, GROUP_CONCAT(name) FROM tb_students_info GROUP BY sex; +--------+------------------------------------+ | sex | GROUP_CONCAT(name) | +--------+------------------------------------+ | female | mary,lisi,green | | male | tom,lily,jim,henry,sean,lisa,jerry | +--------+------------------------------------+ 2 rows in set (0.00 sec)

由結果可以看到,查詢結果分為兩組,sex 字段值為"女"的是一組,值為"男"的是一組,且每組的學生姓名都顯示出來了。

下面根據 tb_students_info 表中的 age 和 sex 字段進行分組查詢。SQL 語句和運行結果如下:

mysql> SELECT age,sex,GROUP_CONCAT(name) FROM tb_students_info GROUP BY age,sex; +------+--------+--------------------+ | age | sex | GROUP_CONCAT(name) | +------+--------+--------------------+ | 22 | female | green | | 22 | male | tom | | 23 | male | lily | | 24 | male | henry,lisa | | 25 | female | mary,lisi | | 26 | male | jim | | 29 | male | jerry | | 39 | male | sean | +------+--------+--------------------+ 8 rows in set (0.00 sec)

上面實例在分組過程中,先按照 age 字段進行分組,當 age 字段值相等時,再把 age 字段值相等的記錄按照 sex 字段進行分組。

多個字段分組查詢時,會先按照第一個字段進行分組。如果第一個字段中有相同的值,MySQL 才會按照第二個字段進行分組。如果第一個字段中的數據都是唯一的,那么 MySQL 將不再對第二個字段進行分組。

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 tb_students_info GROUP BY sex; +--------+------------+ | sex | COUNT(sex) | +--------+------------+ | female | 3 | | male | 7 | +--------+------------+ 2 rows in set (0.00 sec)

結果顯示,sex 字段值為"女"的記錄是一組,有 3 條記錄;sex 字段值為"男"的記錄是一組,有 7 條記錄。

GROUP BY 與 WITH ROLLUP

WITH POLLUP 關鍵字用來在所有記錄的最后加上一條記錄,這條記錄是上面所有記錄的總和,即統計記錄數量。

下面根據 tb_students_info 表中的 sex 字段進行分組查詢,并使用 WITH ROLLUP 顯示記錄的總和:

mysql> SELECT sex,GROUP_CONCAT(name) FROM tb_students_info GROUP BY sex WITH ROLLUP; +--------+----------------------------------------------------+ | sex | GROUP_CONCAT(name) | +--------+----------------------------------------------------+ | female | mary,lisi,green | | male | tom,lily,jim,henry,sean,lisa,jerry | | NULL | mary,lisi,green,tom,lily,jim,henry,sean,lisa,jerry | +--------+----------------------------------------------------+ 3 rows in set (0.00 sec)

查詢結果顯示,GROUP_CONCAT(name) 顯示了每個分組的 name 字段值。同時,最后一條記錄的 GROUP_CONCAT(name) 字段的值剛好是上面分組 name 字段值的總和。

子查詢

子查詢是 MySQL 中比較常用的查詢方法,通過子查詢可以實現多表查詢。子查詢指將一個查詢語句嵌套在另一個查詢語句中。子查詢可以在 SELECT、UPDATE 和 DELETE 語句中使用,而且可以進行多層嵌套。在實際開發時,子查詢經常出現在 WHERE 子句中。

子查詢在 WHERE 中的語法格式如下:

WHERE <表達式> <操作符> (子查詢)

其中,操作符可以是比較運算符和 IN、NOT IN、EXISTS、NOT EXISTS 等關鍵字。

1)IN | NOT IN

當表達式與子查詢返回的結果集中的某個值相等時,返回 TRUE,否則返回 FALSE;若使用關鍵字 NOT,則返回值正好相反。

2)EXISTS | NOT EXISTS

用于判斷子查詢的結果集是否為空,若子查詢的結果集不為空,返回 TRUE,否則返回 FALSE;若使用關鍵字 NOT,則返回的值正好相反。

例 1

使用子查詢在 tb_students_info 表和 tb_course 表中查詢學習 Java 課程的學生姓名,SQL 語句和運行結果如下:

mysql> SELECT name FROM tb_students_info WHERE course_id IN (SELECT id FROM tb_course WHERE course_name = 'Java'); +-------+ | name | +-------+ | tom | | jim | | green | +-------+ 3 rows in set (0.00 sec)

上述查詢過程也可以分為以下 2 步執行,實現效果是相同的。

首先單獨執行內查詢,查詢出 tb_course 表中課程為 Java 的 id,SQL 語句和運行結果如下:

mysql> SELECT id FROM tb_course WHERE course_name = 'Java'; +----+ | id | +----+ | 1 | +----+ 1 row in set (0.00 sec)

可以看到,符合條件的 id 字段的值為 1。

然后執行外層查詢,在 tb_students_info 表中查詢 course_id 等于 1 的學生姓名。SQL 語句和運行結果如下:

mysql> SELECT name FROM tb_students_info WHERE course_id IN (1); +-------+ | name | +-------+ | tom | | jim | | green | +-------+ 3 rows in set (0.00 sec)

習慣上,外層的 SELECT 查詢稱為父查詢,圓括號中嵌入的查詢稱為子查詢(子查詢必須放在圓括號內)。MySQL 在處理上例的 SELECT 語句時,執行流程為:先執行子查詢,再執行父查詢。

例 2

與例 1 類似,在 SELECT 語句中使用 NOT IN 關鍵字,查詢沒有學習 Java 課程的學生姓名,SQL 語句和運行結果如下:

mysql> SELECT name FROM tb_students_info WHERE course_id NOT IN (SELECT id FROM tb_course WHERE course_name = 'Java'); +-------+ | name | +-------+ | mary | | lily | | henry | | sean | | lisi | | lisa | | jerry | +-------+ 7 rows in set (0.01 sec)

可以看出,運行結果與上面的例子剛好相反,沒有學習 Java 課程的是除了 Dany 和 Henry 之外的學生。

例 3

使用=運算符,在 tb_course 表和 tb_students_info 表中查詢出所有學習 Python 課程的學生姓名,SQL 語句和運行結果如下:

mysql> SELECT name FROM tb_students_info WHERE course_id = (SELECT id FROM tb_course WHERE course_name = 'Python'); +-------+ | name | +-------+ | henry | | sean | | jerry | +-------+ 3 rows in set (0.00 sec)

例 4

使用<>運算符,在 tb_course 表和 tb_students_info 表中查詢出沒有學習 Python 課程的學生姓名,SQL 語句和運行結果如下:

mysql> SELECT name FROM tb_students_info WHERE course_id <> (SELECT id FROM tb_course WHERE course_name = 'Python'); +-------+ | name | +-------+ | tom | | mary | | lily | | jim | | lisi | | lisa | | green | +-------+ 7 rows in set (0.00 sec)

可以看出,運行結果與例 3 剛好相反,沒有學習 Python 課程的是除了 Jane 之外的學生。

例 5

查詢 tb_course 表中是否存在 id=1 的課程,如果存在,就查詢出 tb_students_info 表中的記錄,SQL 語句和運行結果如下:

mysql> SELECT * FROM tb_students_info WHERE EXISTS(SELECT course_name FROM tb_course WHERE id=1); +----+-------+------+--------+--------+-----------+ | id | name | age | sex | height | course_id | +----+-------+------+--------+--------+-----------+ | 1 | tom | 22 | male | 172 | 1 | | 2 | mary | 25 | female | 170 | 4 | | 3 | lily | 23 | male | 170 | 2 | | 4 | jim | 26 | male | 176 | 1 | | 5 | henry | 24 | male | 180 | 3 | | 6 | sean | 39 | male | 178 | 3 | | 7 | lisi | 25 | female | 176 | 2 | | 8 | lisa | 24 | male | 181 | 2 | | 9 | green | 22 | female | 188 | 1 | | 10 | jerry | 29 | male | 175 | 3 | +----+-------+------+--------+--------+-----------+ 10 rows in set (0.00 sec)

外層查詢語句接收 TRUE 之后對表 tb_students_info 進行查詢,返回所有的記錄。

EXISTS 關鍵字可以和其它查詢條件一起使用,條件表達式與 EXISTS 關鍵字之間用 AND 和 OR 連接。

例 6

查詢 tb_course 表中是否存在 id=1 的課程,如果存在,就查詢出 tb_students_info 表中 age 字段大于 24 的記錄,SQL 語句和運行結果如下:

mysql> SELECT * FROM tb_students_info WHERE age>24 AND EXISTS(SELECT course_name FROM tb_course WHERE id=1); +----+-------+------+--------+--------+-----------+ | id | name | age | sex | height | course_id | +----+-------+------+--------+--------+-----------+ | 2 | mary | 25 | female | 170 | 4 | | 4 | jim | 26 | male | 176 | 1 | | 6 | sean | 39 | male | 178 | 3 | | 7 | lisi | 25 | female | 176 | 2 | | 10 | jerry | 29 | male | 175 | 3 | +----+-------+------+--------+--------+-----------+ 5 rows in set (0.01 sec)

內層查詢語句從 tb_course 表中查詢到記錄,返回 TRUE。外層查詢語句開始進行查詢。根據查詢條件,從 tb_students_info 表中查詢 age 大于 24 的記錄。

子查詢的功能也可以通過表連接完成,但是子查詢會使 SQL 語句更容易閱讀和編寫。

一般來說,表連接(內連接和外連接等)都可以用子查詢替換,但反過來卻不一定,有的子查詢不能用表連接來替換。子查詢比較靈活、方便、形式多樣,適合作為查詢的篩選條件,而表連接更適合于查看連接表的數據。

總結

以上是生活随笔為你收集整理的MySQL的多表查询的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。