標籤:相互關聯的子查詢 cond 技術 最好 hnu 產生 資料 full join rom
在關係型資料庫系統中,為了滿足第三範式(3NF),需要將滿足“傳遞依賴”的表分離成單獨的表,通過Join 子句將相關表進行串連,Join子句共有三種類型:外串連,內串連,交叉串連;外串連分為:left join、right join、full join;內連結是:inner join,交叉串連是:cross join。
一,Join子句的組成
Join子句由串連表,連線類型和On子句組成,虛擬碼如下:
from Left_Table[inner|left|right|full] join Right_Table [on condition]
1,根據位置,將參與Join的兩個表分為左表和右表
- 在Join子句中,左表和右表進行笛卡爾集合運算,左表中的任意一行都和右表中的所有行進行“組合”,產生虛擬表(Virtual Table),虛擬表的資料行總數Rows(VT)=Rows(left_table)*Rows(right_table);
- 左表和右表進行Join操作,沒有先後順序,這點和Apply子句不同,Apply子句的左表先於右表執行運算;
2,連線類型
在外串連中,left,right和full關鍵字標識Join子句的"保留表":在進行外串連查詢時,保留表中的資料全部返回,不會被on子句過濾。
3,On子句,用雩都虛擬表進行過濾
在on子句運算式中,常用的運算子是相等(=),也可以使用不等(>,<>),like等運算子,返回的結果是布爾值;
on子句運算式的運算元,可以是表列(Column),常量,運算式,例如;
- on left_table.column=right_table.column
- on left_table.column=value
- on left_table.column+xx=value
- 不過濾:比如設定on 1=1
4,On子句決定Join的順序
如果一個查詢包含多個Join子句,那麼On子句決定Join子句執行的順序;執行Join的順序是:tb和tc先執行串連操作,ta和tb後執行串連操作。
from taleft join tbleft join tc on tb.column=tc.column on ta.column=tb.column
5,On子句過濾和Where子句過濾
On子句的執行順序先於where子句,在進行過濾時,On子句無法過濾保留表,但是where子句能夠過濾保留表;
對於inner join,由於沒有保留表,所以,在On子句和where子句中進行過濾,結果是一樣的,但是,建議明確區分where子句和on子句的職能,on子句用於過濾串連的虛擬表,where用於對最終的結果集進行過濾。
例如:在On子句中,ta.column2=value1 不會過濾左表ta,如果不滿足該條件,那麼右表相應的資料列設定為NULL,left關鍵字保證左表中的所有資料行都返回;where子句(ta.column3=value2)過濾左表ta;
from taleft join tb on ta.column1=ta.column1 and ta.column2=value1where ta.column3=value2
二,建立測試代碼
View Code
三,left join(左外串連)
1,left join演算法
把左表作為保留表,返回左表的全部資料,對於右表中不匹配on子句條件資料行,返回NULL;
select * from dbo.ta a left join dbo.tb b on a.a=b.ca
2,使用常量過濾左表
在左外串連中,左表會返回所有資料,對於“and left_table.column=value”,是在第一個條件成立時,對返回的結果進行過濾,而左表資料會全部返回,當不滿足條件時,設定右表資料為NULL;
select * from dbo.ta a left join dbo.tb b on a.a=b.ca and a.a=1
3,使用where子句過濾左表
where子句是對結果集進行過濾的最後一個Filter
select * from dbo.ta a left join dbo.tb b on a.a=b.ca where a.a=1
4,使用where子句過濾右表
如果使用where子句對右表進行過濾,一般可以轉換成inner join
select * from dbo.ta a left join dbo.tb b on a.a=b.ca where b.ca=1
四,right join(右外串連)
right join 演算法是把右表作為保留表,將右表中的資料全部顯示出來,對於左表中匹配不到的資料行,將其欄位值設定為NULL;
select * from dbo.ta a right join dbo.tb b on a.a=b.ca
五,inner join(內串連)
演算法是:inner join沒有保留表,只返回滿足 on 子句條件的資料行,對於不滿足on子句條件的資料行,不返回
select * from dbo.ta a inner join dbo.tb b on a.a=b.ca
六,full join(全串連)
演算法是:full join 把左表和右表都作為保留表,如果左表和右表中的資料行滿足On子句條件,那麼顯示資料行資料,如果不匹配,則相應的欄位設定為null。
select * from dbo.ta a full join dbo.tb b on a.a=b.ca
七,cross join(交叉串連)
演算法是:cross join 是對左表和遊標進行笛卡爾乘積,cross join沒有on子句,笛卡爾乘積是將左表中的任意一行資料和右表中的所有資料行進行組合,cross join 將笛卡爾乘積後的結果直接顯示出來
select * from dbo.ta a cross join dbo.tb b
八,自串連用於累積求和
自串連是指一個table 和自己進行join,例如以下語句,表 dbo.ta和自身進行inner join,計算b欄位的累積和。
select t1.a,sum(t2.b) as b from dbo.ta t1 inner join dbo.ta as t2 on t1.a>=t2.a group by t1.a
在實際的產品環境中,經常利用自連接進行累加求和的計算,例如有如下一個Table:dbo.FinanceMonth,每個月的產量是Quantity,計算一年內到該月份為止的所有月份的Quantity的累積值。
View Code
使用自連結計算累積值
select a.MonthNum,sum(b.quantity) as TotalQuantity from dbo.FinanceMonth a inner join dbo.FinanceMonth b on a.MonthNum>=b.MonthNum group by a.MonthNum order by a.MonthNum
九,apply 用法
1,join和apply的區別
join 子句左表和右表的計算是不分先後的,從效能上考慮,最好把小表作為左表,當右表資料量大的時候,會減少查詢的時間消耗。apply子句的左表和右表是區分先後順序的,apply是先計算左表,後計算右表,因此apply子句不是集合動作陳述式。如果右表是一個資料表值函式,apply會先取得左表中的一行記錄的值,作為參數值傳遞給資料表值函式進行計算,左表中的一行記錄和“右表”進行笛卡爾乘積做為最終結果。如果右表查詢出來的結果是空的,那麼右表欄位設定為null。
select * from dbo.ta a outer apply (select * from dbo.tb b where a.a=b.ca) p
從查詢結果上看,跟left join是相同的,但是在效能上,outer apply 比left join要差,因為TSQL 擅長集合操作,使用集合的思想編寫的代碼效能一般都很高,left join是集合動作陳述式,效能優於outer apply
雖然apply效能低,但是也有其用武之地,當需要按照順序進行串連時,apply是最好的選擇。
2,apply的兩種用法
outer apply 和cross apply的相同點是:
- 先計算左表,後計算右表;
- 對左表中的每一行記錄,右表都要“逐行”計算,類似於相互關聯的子查詢,實際上,TSQL對apply進行最佳化之後,並不是逐行,而是逐N行;
outer apply 和cross apply的不同點是:
- outer apply:將左表作為保留表,如果右表沒有匹配行,那麼右表中的欄位會設定為null,類似於left join。
- cross apply:沒有保留表,對於左表中的一行記錄,如果右表中沒有匹配行,那麼該行記錄不顯示在最終結果集中,類似於inner join。
select * from dbo.ta a cross apply (select * from dbo.tb b where a.a=b.ca) p
十,join語句的應用
1,使用cross join能夠快速產生大量順序數字
cross join的結果集中資料行的數量是:左表資料行數和右表資料行數的乘積,由於每個table都有10個數字(從0到9),4個table進行cross join能夠快速產生10的4次方,即10000個順序數字。
;with num as ( select n from(values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) as p(n) ) select a.n+b.n*10+c.n*100+d.n*1000 as n --into dbo.num from num across join num b cross join num c cross join num d order by n
2,使用left join 查詢不存在於右表的資料行
如果左表中的資料不存於右表,那麼右表的欄位是null,通過在 where 子句中設定filter,能夠查詢出存在於左表,但是不存在於右表的資料行
select * from dbo.ta t1 left join dbo.tb t2 on t1.a=t2.ca where t2.ca is null;
Join 和 App