一,子查詢簡介:
子查詢就是嵌套在主查詢中的查詢。
子查詢可以嵌套在主查詢中所有位置,包括SELECT、FROM、WHERE、ORDER BY。但并不是每個位置嵌套子查詢都是有意義并實用的。
子查詢必須“自身就是一個完整的查詢”。即,它必須至少包括一個SELECT子句和FROM子句。
子查詢的分類:
相關子查詢:
執行依賴于外部查詢的資料。(就是table1在該select外面,而select裡面table1.xx=table2.xx)
外部查詢傳回一行 ,子查詢就執行一次。(對于該select,裡面的子select會重複很多次執行)
非相關子查詢:
獨立于外部查詢的子查詢。
子查詢總共執行一次,執行完畢後後将值傳遞給外部查詢。
二,子查詢的傳回:
一個子查詢會傳回一個标量(單一值)、一個行、一個列或一個表(一行或多行及一列或多列)。這些子查詢被稱為标量、列、行和表子查詢
1,單行單列,聚合(标量):
傳回的結果集為單個的子查詢,叫做單行子查詢。單行比較符有: =、 >、>=、
2,單行多列:
SELECT * FROM t1 WHERE (1,2) = (SELECT column1,column2 FROM t2);
SELECT* FROM t1 WHERE ROW(1,2) = (SELECT column1, column2 FROM t2);
如果在表t2的一個行中,column1=1并且column2=2,則查詢結果均為TRUE。
表達式(1,2)和ROW(1,2)有時被稱為行構造符。兩者是等同的,在其它的語境中也是合法的。例如,以下兩個語句在語義上是等同的(但是目前隻有第二個語句可以被優化):
SELECT * FROM t1 WHERE (column1,column2) = (1,1);
SELECT* FROM t1 WHERE column1 = 1 AND column2 = 1;
3,單列:
傳回的結果集為多個的子查詢,為多行子查詢,多行子比較符有 IN(等于列中任意一個)、ANY(和子查詢傳回的某個值比較),ALL(和子查詢傳回的所有值比較)
NOT IN 是 <>ALL 的别名
IN 是 = ANY 的别名
4,多行多列的子表:
可以用在where子句中的 exists,not exists的查詢條件;或者from子句後面(此時子表必須命名,并且不能為有關聯的子查詢)
五,在FROM中嵌套
from下的子查詢 相當于傳回一張表,并且要強制取名。
from子句中的子查詢不能為有關聯的子查詢。
在SELECT語句的FROM子句中,子查詢是合法的。實際的文法是:
SELECT ... FROM (subquery) [AS] name ...
[AS]name子句是強制性的,因為FROM子句中的每個表必須有一個名稱。在子查詢選擇清單中的任何列都必須有唯一的名稱。假設有如下一個表:
CREATE TABLE t1 (s1 INT, s2 CHAR(5), s3 FLOAT);
下面使用了示例表,解釋了在FROM子句中如何使用子查詢:
INSERT INTO t1 VALUES (1,'1',1.0);
INSERT INTO t1 VALUES (2,'2',2.0);
SELECT sb1,sb2,sb3
FROM (SELECT s1AS sb1, s2 AS sb2, s3*2 AS sb3 FROM t1) ASsb
WHERE sb1> 1;//結果:2, '2', 4.0。
下面是另一個例子:假設您想了解一個分類後的表的一組和的平均值。采用如下操作:
SELECT AVG(SUM(column1)) FROM t1 GROUP BY column1;
不過,本查詢提供所需的資訊:
SELECT AVG(sum_column1)
FROM (SELECT SUM(column1)ASsum_column1
FROM t1 GROUP BY column1)AS t1;
注意,在子查詢中使用的列名稱(sum_column1)被整理到外部查詢中。
六,在SELECT中嵌套:
select中的子查詢如果是相關子查詢,一般可以和join關聯查詢轉換
現有表兩張:一張學生表、一張班表。id相關聯
學生資訊和班級名稱位于不同的表中,要在同一張表中查出學生的學号、姓名、班級名稱:
SELECT s.student_id,s.student_name,(SELECT class_name FROM t_class c WHERE c.class_id=s.class_id) FROM t_student s GROUP BY s.student_id;
七,在WHERE中嵌套:
現要查出C語言成績最高的學生的資訊:
SELECT * FROM t_student WHERE student_subject='C語言' AND student_score>=
ALL (SELECT student_score FROM t_student WHERE student_subject='C語言') ;
這裡出現了一個ALL,其為子查詢運算符
分類:
–ALL運算符
和子查詢的結果逐一比較,必須全部滿足時表達式的值才為真。
–ANY運算符
和子查詢的結果逐一比較,其中一條記錄滿足條件則表達式的值就為真。
–EXISTS/NOT EXISTS運算符
EXISTS判斷子查詢是否存在資料,如果存在則表達式為真,反之為假。NOT EXISTS相反。
在子查詢或相關查詢中,要求出某個列的最大值,通常都是用ALL來比較,大意為比其他行都要大的值即為最大值。
要查出C語言成績比李四高的學生的資訊:
SELECT * FROM t_student WHERE student_subject='C語言' AND student_score >
(SELECT student_score FROM t_student WHERE student_name='李四' AND student_subject='C語言');
通過上面兩例,應該可以明白子查詢在WHERE中嵌套的作用。通過子查詢中傳回的列值來作為比較對象,在WHERE中運用不同的比較運算符來對其進行比較,進而得到結果。
現在我們回到最開始的問題,怎麼查出每門課最高成績的學生的資訊:(這個也是相關子查詢)
SELECT * FROM t_student s1 WHERE s1.student_score >=
ALL(SELECT s2.student_score FROM t_student s2 WHERE s1.`student_subject`=s2.student_subject);
這裡就是上文提到的别名的第二種用法,主、子查詢對同一張表操作,區分開位于内外表中相同的列名。
八,order by子查詢
需求舉例:按平均值排序
select 學号,姓名,專業名 from xs where 專業名 = '計算機'
order by (select avg() from xs_kc group by xs_kc.學号 having xs_kc.學号=xs.學号);
三,EXISTS和NOT EXISTS
該文法可以了解為:将主查詢的資料,放到子查詢中做條件驗證,根據驗證結果(TRUE 或 FALSE)來決定主查詢的資料結果是否得以保留。
#exists的例子
SELECT s.Sname FROM student s WHERE EXISTS
(SELECT * FROM sc, course c WHERE sc.sno = s.sno AND sc.cno = c.cno AND c.cname = '信号與系統')
//裡面還用到了from多個表的情況,from多個表的時候按條件笛卡爾積
#not exists的例子
SELECT Sname FROM Student WHERE NOT EXISTS
(SELECT * FROM Course WHERE NOT EXISTS
(SELECT * FROM SC WHERE Sno=Student.Sno AND Cno=Course.Cno) );
四,子查詢和join轉換情況
#使用join
update member set nickname = member_update_store.nickname from member joinmember_update_store
on (member.id=member_update_store.memberid)
where member.id in(1,2,3) and member_update_store.nickname is not null;
#使用子查詢
update member set nickname = (select nickname frommember_update_store
where member_update_store.memberid = member.id and member_update_store.nickname is not null)
where id in(1,2,3);