mysql入門_子查詢
子查詢
定義:一個查詢語句中巢狀一個或者多個查詢語句,內層巢狀的查詢語句稱為子查詢。
意義:普通多表查詢先構建多張表的笛卡爾積在笛卡爾積結果上進行過濾,使用子查詢能夠在建立多表笛卡爾積時對子表先進行一遍過濾,這樣能夠有效降低笛卡爾結果集的數量,降低記憶體消耗,提高查詢效率。
單行子查詢:
子查詢的結果是多行單列,子查詢的結果作為主查詢的where判斷輸入
原始表資訊:
mysql> select * from teacher;
+-----+--------+------+---------------------+-----------+-----------------+
| tno | tname | tsex | tbirthday | prof | depart |
+-----+--------+------+---------------------+-----------+-----------------+
| 804 | 李誠 | 男 | 1958-12-02 00:00:00 | 副教授 | 計算機系 |
| 825 | 王萍 | 女 | 1972-05-05 00:00:00 | 助教 | 計算機系 |
| 831 | 劉冰 | 女 | 1977-08-14 00:00:00 | 助教 | 電子工程系 |
| 856 | 張旭 | 男 | 1969-03-12 00:00:00 | 講師 | 電子工程系 |
+-----+--------+------+---------------------+-----------+-----------------+
mysql> select * from course;
+-------+-----------------+-----+
| cno | cname | tno |
+-------+-----------------+-----+
| 3-105 | 計算機導論 | 825 |
| 3-245 | 作業系統 | 804 |
| 6-166 | 數位電路 | 856 |
| 9-888 | 高等數學 | 831 |
+-------+-----------------+-----+
子查詢結果是單行單列主查詢的限定可以使用“=”
mysql> SELECT t.* FROM teacher AS t WHERE t.tno=(SELECT c.tno FROM course AS c WHERE c.cname="計算機導論");
+-----+--------+------+---------------------+--------+--------------+
| tno | tname | tsex | tbirthday | prof | depart |
+-----+--------+------+---------------------+--------+--------------+
| 825 | 王萍 | 女 | 1972-05-05 00:00:00 | 助教 | 計算機系 |
+-----+--------+------+---------------------+--------+--------------+
子查詢結果是多行單列主查詢的限定可以使用關鍵字in
mysql> SELECT t.* FROM teacher AS t WHERE t.tno IN (SELECT c.tno FROM course AS c WHERE c.cname IN ("計算機導論", "作業系統"));
+-----+--------+------+---------------------+-----------+--------------+
| tno | tname | tsex | tbirthday | prof | depart |
+-----+--------+------+---------------------+-----------+--------------+
| 825 | 王萍 | 女 | 1972-05-05 00:00:00 | 助教 | 計算機系 |
| 804 | 李誠 | 男 | 1958-12-02 00:00:00 | 副教授 | 計算機系 |
+-----+--------+------+---------------------+-----------+--------------+
多行子查詢
多行子查詢中子查詢的結果返回多行多列,作為臨時表來構建最終多表的查詢笛卡爾積的子表。
學生表和成績表的基表
mysql> select * from student;
+-----+--------+------+---------------------+-------+----------+
| sno | sname | ssex | sbirthday | class | romemate |
+-----+--------+------+---------------------+-------+----------+
| 101 | 李軍 | 男 | 1976-02-20 00:00:00 | 95033 | 103 |
| 103 | 陸君 | 男 | 1974-06-03 00:00:00 | 95031 | 101 |
| 105 | 匡明 | 男 | 1975-10-02 00:00:00 | 95031 | 108 |
| 107 | 王麗 | 女 | 1976-01-23 00:00:00 | 95033 | 108 |
| 108 | 曾華 | 男 | 1977-09-01 00:00:00 | 95033 | 109 |
| 109 | 王芳 | 女 | 1975-02-10 00:00:00 | 95031 | 108 |
| 111 | jIMe | Man | NULL | NULL | 101 |
+-----+--------+------+---------------------+-------+----------+
mysql> select * from score;
+----+-----+-------+--------+
| id | sno | cno | degree |
+----+-----+-------+--------+
| 1 | 103 | 3-245 | 86 |
| 2 | 105 | 3-245 | 75 |
| 3 | 109 | 3-245 | 68 |
| 4 | 103 | 3-105 | 92 |
| 5 | 105 | 3-105 | 88 |
| 6 | 109 | 3-105 | 76 |
| 7 | 103 | 3-105 | 64 |
| 8 | 105 | 3-105 | 91 |
| 9 | 109 | 3-105 | 78 |
| 10 | 103 | 6-166 | 85 |
| 11 | 105 | 6-166 | 79 |
| 12 | 109 | 6-166 | 81 |
+----+-----+-------+--------+
/*查詢成績大於該課程平均成績的學生資訊*/
/*步驟一:查詢每門課程的平均成績*/
mysql> SELECT sc.cno,AVG(sc.degree) AS avg_degree FROM score AS sc GROUP BY sc.cno;
+-------+------------+
| cno | avg_degree |
+-------+------------+
| 3-105 | 81.5000 |
| 3-245 | 76.3333 |
| 6-166 | 81.6667 |
+-------+------------+
/*步驟二:過濾成績大於平均成績成績表*/
mysql> SELECT sc_last.* FROM score AS sc_last INNER JOIN (SELECT sc.cno,AVG(sc.degree) AS avg_degree FROM score AS sc GROUP BY sc.cno) AS sc_avg ON sc_last.cno=sc_avg.cno AND sc_last.degree >= sc_avg.avg_degree;
+----+-----+-------+--------+
| id | sno | cno | degree |
+----+-----+-------+--------+
| 1 | 103 | 3-245 | 86 |
| 4 | 103 | 3-105 | 92 |
| 5 | 105 | 3-105 | 88 |
| 8 | 105 | 3-105 | 91 |
| 10 | 103 | 6-166 | 85 |
+----+-----+-------+--------+
/*步驟三:將學生表和步驟二中的臨時表進行多表查詢*/
mysql> SELECT st.*,sc_tmp.cno,sc_tmp.degree FROM student AS st INNER JOIN (SELECT sc_last.* FROM score AS sc_last INNER JOIN (SELECT sc.cno,AVG(sc.degree) AS avg_degree FROM score AS sc GROUP BY sc.cno) AS sc_avg ON sc_last.cno=sc_avg.cno AND sc_last.degree >= sc_avg.avg_degree) AS sc_tmp ON st.sno=sc_tmp.sno;
+-----+--------+------+---------------------+-------+----------+-------+--------+
| sno | sname | ssex | sbirthday | class | romemate | cno | degree |
+-----+--------+------+---------------------+-------+----------+-------+--------+
| 103 | 陸君 | 男 | 1974-06-03 00:00:00 | 95031 | 101 | 3-245 | 86 |
| 103 | 陸君 | 男 | 1974-06-03 00:00:00 | 95031 | 101 | 3-105 | 92 |
| 105 | 匡明 | 男 | 1975-10-02 00:00:00 | 95031 | 108 | 3-105 | 88 |
| 105 | 匡明 | 男 | 1975-10-02 00:00:00 | 95031 | 108 | 3-105 | 91 |
| 103 | 陸君 | 男 | 1974-06-03 00:00:00 | 95031 | 101 | 6-166 | 85 |
+-----+--------+------+---------------------+-------+----------+-------+--------+