1. 程式人生 > >【Transact-SQL】SQL Server自動把left join自動轉化為inner join、以及關聯時的資料重複問題

【Transact-SQL】SQL Server自動把left join自動轉化為inner join、以及關聯時的資料重複問題

1、SQL Server自動把left join自動轉化為inner join的問題:

下面的兩個語句都是left join的,但是一個卻轉化成了 inner join

drop table a,B
go

create table a(id int)

insert into a
select 1 union all
select 2

create table b(id int,xxx varchar(10))

insert into b
select 1,'xxx' union all
select 2,'xx'
go


--這個還是left join
select *
from a 
left join b
       on a.id = b.id and b.xxx = 'xxx'
/*
id	id	xxx
1	1	xxx
2	NULL	NULL
*/ 
 

select * --這個就是轉化為inner join
from a 
left join b
       on a.id = b.id 
where b.xxx = 'xxx'
/*
id	id	xxx
1	1	xxx
*/

下面的圖是執行計劃:


2、下面的語句,執行後會出來幾條記錄呢?

select*
from 
(
	select 1 as id
)a

left join
(
	select 1 as id
	union all
	select 1 
)b
 on a.id = b.id
 
left join 
(
	select 1 as id
	union all
	select 1 
)c
 on a.id = c.id


 之所以會想到這個問題,是因為發現最近寫的報表總是執行結果不對,數字偏大,報表的邏輯要比上面的語句複雜,但問題是一樣的。

首先,查詢結果要求出來明細資料,由於表a關聯了表b,

雖然表a中沒有重複記錄,但是表b中有重複記錄,導致表a的一條記錄與表b的2條記錄關聯時,結果集會有2條,然後再把產生的結果集再與表c關聯,這時由於c表中也有重複資料,那麼最後的結果集就會是4條。

看上去和笛卡爾積一樣2*2 = 4,但其實是由於表b和表c都有重複記錄,導致關聯以後出現大量的重複資料,這個問題在寫SQL語句的時候,一定要非常注意。

如果來解決這個問題呢?

一般可以先單獨對有重複資料表進行去重,或者group by並按照需求進行聚合計算,然後再進行關聯,這樣就不會導致數字偏大。