在SQL的查詢語句select …. from …中,跟在from子句后面的通常是一張擁有定義的實體表,而有的時候我們會用子查詢來扮演實體表的角色,這個在from子句中的子查詢會返回一個結果集,這個結果集可以像普通的實體表一樣查詢、連接,這個子查詢的結果集就叫做衍生表。
文章目錄
- 一、衍生表簡介
- 1.1 衍生表基本用法
- 1.2 自定義列名
- 1.3 衍生表的局限
一、衍生表簡介
衍生表常用在需要對數據進行臨時處理的場景,即對表直接查詢無法得出結果,需要對數據進行加工,然后在加工基礎上與原數據再次進行連接,才能得出結果。
示例數據準備
例如下面一的張考試成績表,subject_id代表不同的科目,score代表分數:
create table exam(
id int not null auto_increment primary key,
subject_id int,
student varchar(12),
score int);insert into exam values(null,1,'小紅',89), (null,1,'小橙',76), (null,1,'小黃',89),(null,1,'小綠',95), (null,2,'小青',77), (null,2,'小藍',83), (null,2,'小紫',99);select * from exam;
1.1 衍生表基本用法
現要求:找出每個科目得分最高那條記錄,這個問題需要拆分成2步完成:
第一步:找出每個科目的最高分
select subject_id, max(score) score from exam group by subject_id;
第二步:將上一步的結果與exam表進行連接,找出具體的記錄:
select e.* from exam e, (select subject_id, max(score) score from exam group by subject_id) d
where d.subject_id=e.subject_id and d.score=e.score;
? 這里將第一步的查詢放在括號中,并取一個別名d。
? 通過別名d,MySQL可以像引用實體表一樣引用子查詢的結果集(衍生表)。
1.2 自定義列名
在給衍生表定義別名時,可以同時定義列名,方法是在別名后的括號內列出列名,要注意列名的數量要和子查詢返回的列數量相同:
select a, b, d from (select 1,2,3,4) d(a,b,c,d);
1.3 衍生表的局限
衍生表目前的局限是它是一個獨立的子查詢,在生成結果集之前無法和from表中的其他表產生關聯,如果產生衍生表的子查詢成本非常高,而最后與其他表連接后只使用了一小部分數據,那么這個性能浪費是非常嚴重的。
例如上面的例子中,如果表中有10萬個科目,而我最終結果只涉及2個科目,那么在衍生表中對10萬個科目進行group by顯然是沒有必要的,這種情況我們需要提前將外層謂語條件(where)傳入衍生表中,避免處理不必要的數據,但這也意味著謂語條件在外層寫了一遍,必須在衍生表中再寫一遍,增加了SQL復雜度。
在MySQL 8.0.14版本后,通過橫向衍生表(lateral關鍵字),可以在衍生表中引用from子句中之前出現的表,可以完美解決上述局限。