2012-10-02 20 views
2


的SQL Server將多個數據集,而不會考慮三個表TA,TB,TC重複數據

Ta(ID, Field1) 
Tb(ID, Field2) 
Tc(ID, Field3) 

鑑於數據例如:

Ta 
ID Field1 
--------- 
1 A 
1 B 

Tb 
ID Field2 
--------- 
1 C 
1 D 
2 E 

Tc 
ID Field3 
--------- 
1 F 
2 G 
2 H 

問: 我怎樣才能加入這個要返回的數據:

ID Field1 Field2 Field3 
----------------------- 
1 A  C  F 
1 B  D  NULL 
2 NULL E  G 
2 NULL NULL H 

我認爲我可以通過外連接實現這一點,但似乎並非如此。只要我帶回沒有重複行的所有信息,分組順序並不重要。

只是爲了澄清。只要結果集返回最小行數中的所有數據,我並不介意使用哪種組合。下面是我想要做的更實際的例子:

給定一個人,叫他約翰。他有兩個電話號碼和三個電子郵件地址:

PID Email 
--------- 
John [email protected] 
John [email protected] 
John [email protected] 

PID Tel 
-------- 
John 011 
John 022 

我要回:

PID Email   Tel 
---------------------- 
John [email protected] 011 
John [email protected] 022 
John [email protected] NULL 
+3

爲什麼是分配給ID = 3的最後一排? – Lamak

+1

'1 A D F'?和'1 B C F'?爲什麼不回報他們,他們顯然是從你的回報中失蹤,不是嗎?在你迴應之前,停下來思考,也許你會意識到真正的問題與你的需求... –

+3

你的組合似乎取決於原始表中的行的排序。在SQL(和SQL Server)中,表中行的順序未指定。你有行號或標識列或日期或確定訂購的東西嗎? –

回答

3

您可以用下面的接近:正如我所說的

select coalesce(ta.id, tb.id, tc.id), ta.field1, tb.field2, tc.field3 
from (select ta.*, row_number() over (partition by id order by (select NULL)) as seqnum 
     from ta 
    ) ta full outer join 
    (select tb.*, row_number() over (partition by id order by (select NULL)) as seqnum 
     from tb 
    ) tb 
    on ta.id = tb.id and 
     ta.seqnum = tb.seqnum 
    (select tc.*, row_number() over (partition by id order by (select NULL)) as seqnum 
     from tc 
    ) tc 
    on coalesce(ta.id, tb.id) = tc.id and 
     coalesce(ta.seqnum, tb.seqnum) = tc.seqnum 
group by coalesce(ta.id, tb.id, tc.id), 
     coalesce(ta.seqnum, tb.seqnum, tc.seqnum) 
order by 1, 2 

,不過,在我的評論中,表格中行的排序不能保證,所以這些可能不會按照您期望的順序出現。有了您的樣本數據,你可以使用:

over (partition by id order by field<n>) 

如果字段定義排序

3

這裏有一個替代方案,使用CTE的和聯盟,與MIN排除空值。它不能保證排序,但正如你所說,只要身份證全都存在,你就不在意。

SQL小提琴here

WITH TaRanked AS 
(
    SELECT ROW_NUMBER() OVER (PARTITION BY ID ORDER BY Field1) as Rnk, ID, Field1 
    FROM Ta 
), 
TbRanked AS 
(
    SELECT ROW_NUMBER() OVER (PARTITION BY ID ORDER BY Field2) as Rnk, ID, Field2 
    FROM Tb 
), 
TcRanked AS 
(
    SELECT ROW_NUMBER() OVER (PARTITION BY ID ORDER BY Field3) as Rnk, ID, Field3 
    FROM Tc 
), 
TUnion AS 
(
    SELECT Rnk, ID, Field1, NULL AS Field2, NULL AS Field3 
     FROM TaRanked 
    UNION ALL 
    SELECT Rnk, ID, NULL, Field2, NULL 
     FROM TbRanked 
    UNION ALL 
    SELECT Rnk, ID, NULL, NULL, Field3 
     FROM TcRanked 
) 
SELECT ID, MIN(Field1), MIN(Field2), MIN(Field3) 
    FROM TUnion 
    GROUP BY ID, Rnk 
    ORDER BY ID, Rnk 

結果是

1 A  C  F 
1 B  D  (null) 
2 (null) E  G 
2 (null) (null) H 
+0

由於Gordon Linoff的回答爲我工作,我沒有機會嘗試此操作。也就是說,這似乎是以相同的方式進行的,但以更具可讀性的方式(+1)。我會讓選民從這裏拿走它! :) –

+0

Gordon是正確的 - 需要分區來保證最小行數。這也會設置所需的順序。我已更新。 – StuartLC

相關問題