SQL Distinct處理多列問題
今天在做SSIS的ETL工作時,其中一個left join元件的執行結果總是會多出一些記錄。分析了一下,該問題的原因是右表中作為關聯的那一列資料有重複。left join的執行策略可以理解為根據左表的每一條記錄的關聯欄位去對照右表的關聯欄位,如果右表的關聯欄位存在重複,就會生成重複的記錄。如果左表存在重複而右表無重複,則不會多出來記錄。舉個例子,如果左表a和右表b的資料分別如下所示
ID | Name |
1 | 張三 |
2 | 李四 |
3 | 王五 |
4 | 王陸 |
ID | Description |
1 | 內聯部 |
1 | 系學生會 |
2 | 外聯部 |
3 | 團委 |
這時如果用ID作為關聯欄位用a表left join b表,結果會產生5條記錄,比左表多一條。(順便提一下,如果右表不重複,則left join的結果數會與左表相等)
ID | Name | Description |
1 | 張三 | 內聯部 |
1 | 張三 | 系學生會 |
2 | 李四 | 外聯部 |
3 | 王五 | 團委 |
4 | 王陸 | NULL |
實際上,我想要的結果是與左表a一一對應,不要有重複的記錄。這可以通過SSIS的lookup元件實現,但是效率會很低。因此就想到把右表中的重複記錄去除掉再join兩張表。首先自然地想到用distinct函式去重
SELECT DISTINCT ID, Description
FROM B
結果卻是1條記錄都沒去掉,因為Distinct是作用於多列的,也就是說必須要ID和Description全都相同的才會被剔除。
在網上搜了一下,有人說用 select *, count(distinct name) from table group by name 這樣的語句是可行的,但我在SQL Server裡面試了一下會報錯。只好自己動手,豐衣足食啦,想了一下,其實可以用下面的語句
SELECT ID, Max(Description) AS Description
FROM B
GROUP BY ID
進一步的思考後發現,SQL Server中有First_Value和Last_Value函式,也可以實現
SELECT DISTINCT ID, FIRST_VALUE(Description) OVER (PARTITION BY ID
ORDER BY Description) AS Description FROM B
第二種方法中Partition by的引數必須是ID,Order by的引數可以調整,這就使得該方法更加靈活。這兩種方法經實測效率差不多,第一種稍微快一點點。不過遺憾的是SSIS中不支援第二種方法,只能用第一種group by的方式。