JOIN 2 Tables从2列获取唯一值

时间:2013-07-22 18:32:43

标签: tsql join

我有一个(我认为)复杂的问题,并且不知道如何在SQL(全天)中这样做。我已经把逻辑转了几次,总是缺少一些东西。

两个表之间存在一个连接,它对第三个表有不同的FK引用。

如何加入这两个表,所以我确信所有的FK组合都会被呈现,而且所有这些组合都是唯一的? 我需要将2个FK列合二为一,所以我以后可以加入第3列。空值是可能的。分组不可能,因为我需要知道记录的来源(结果中需要Id_1和Id_2)

示例代码:

DECLARE @T1 TABLE (Id int, CommonId int, FK_Id_1 int)
DECLARE @T2 TABLE (Id int,CommonId int, FK_Id_2 int)


INSERT INTO @T1 VALUES (1,1,1)
INSERT INTO @T1 VALUES (2,1,2)
INSERT INTO @T1 VALUES (3,2,3)
INSERT INTO @T1 VALUES (4,3,NULL)
INSERT INTO @T1 VALUES (5,4,NULL)

INSERT INTO @T2 VALUES (11,1,1)
INSERT INTO @T2 VALUES (12,2,2)
INSERT INTO @T2 VALUES (13,2,3)
INSERT INTO @T2 VALUES (14,4,5)

SELECT t1.Id as Id_1,t2.Id as Id_2, t1.CommonId, t1.FK_Id_1, t2.FK_Id_2,
COUNT(t1.FK_Id_1) OVER (PARTITION BY t1.FK_Id_1) AS T1_RANK,
COUNT(t2.FK_Id_2) OVER (PARTITION BY t2.FK_Id_2)AS T2_RANK
FROM @T1 t1 
 FULL JOIN @T2 t2 on t1.CommonId = t2.CommonId
ORDER BY CommonId

此查询返回此信息:

Id_1        Id_2        CommonId    FK_Id_1     FK_Id_2     T1_RANK     T2_RANK
----------- ----------- ----------- ----------- ----------- ----------- -----------
1           11          1           1           1           1           2
2           11          1           2           1           1           2
3           12          2           3           2           2           1
3           13          2           3           3           2           1
4           NULL        3           NULL        NULL        0           0
5           14          4           NULL        5           0           1

我需要以某种方式让它看起来像这样:

Id_1        Id_2        CommonId    FK_Id
----------- ----------- ----------- -----------
1           11          1           1
2           11          1           2
3           12          2           2
3           13          2           3
4           NULL        3           NULL
5           14          4           5

我做了SELECT COALESCE(FK_Id_1,FK_Id_2) AS FK_Id之类的事情,但这总是优先选择T1。我正在考虑根据重复值切换优先级的方法。

我有一个看起来像这样的丑陋解决方案,但我正在寻找更好的想法。

;WITH tmp as (
SELECT t1.Id as Id_1,t2.Id as Id_2, t1.CommonId, t1.FK_Id_1, t2.FK_Id_2,
COUNT(t1.FK_Id_1) OVER (PARTITION BY t1.FK_Id_1) AS T1_RANK,
COUNT(t2.FK_Id_2) OVER (PARTITION BY t2.FK_Id_2)AS T2_RANK
FROM @T1 t1 
FULL JOIN @T2 t2 on t1.CommonId = t2.CommonId)
SELECT Id_1, Id_2, CommonId, 
CASE 
    WHEN T1_RANK > T2_RANK THEN COALESCE(FK_Id_2,FK_Id_1)
    WHEN T2_RANK > T1_RANK THEN COALESCE(FK_Id_1,FK_Id_2)
END AS FK_Id
FROM tmp
ORDER BY CommonId

我不知道我是否正确解释了整个情况,我必须加入表格,因为我有其他列只来自T1和T2(不能UNION-&gt; DISTINCT - 这也会选择NULL)< / p>

1 个答案:

答案 0 :(得分:0)

选择CommonId,然后完全加入两个表。

下面的查询与您想要的结果匹配100%。

;WITH cte AS (
    SELECT CommonId FROM @T1
    UNION SELECT CommonId FROM @T2
)
SELECT t1.Id AS Id_1, t2.Id AS Id_2, cte.CommonId, ISNULL(t2.FK_Id_2, t1.FK_Id_1) AS FK_Id 
FROM cte
FULL OUTER JOIN @T1 t1 ON cte.CommonId = t1.CommonId
FULL OUTER JOIN @T2 t2 ON cte.CommonId = t2.CommonId

请注意FK_Id的结果随谓词ISNULL中的列顺序而变化

ISNULL(t2.FK_Id_2, t1.FK_Id_1)ISNULL(t1.FK_Id_1, t2.FK_Id_2)

不同

在我看来,这个替代版本更符合您的要求,因为它采用了FK的两个选项。

;WITH cte AS (
    SELECT CommonId FROM @T1
    UNION SELECT CommonId FROM @T2
)
SELECT t1.Id AS Id_1, t2.Id AS Id_2, cte.CommonId, ISNULL(t2.FK_Id_2, t1.FK_Id_1) AS FK_Id--, cte.CommonId,   * 
FROM cte
FULL OUTER JOIN @T1 t1 ON cte.CommonId = t1.CommonId
FULL OUTER JOIN @T2 t2 ON cte.CommonId = t2.CommonId
UNION 
SELECT t1.Id AS Id_1, t2.Id AS Id_2, cte.CommonId, ISNULL(t1.FK_Id_1, t2.FK_Id_2) AS FK_Id--, cte.CommonId,   * 
FROM cte
FULL OUTER JOIN @T1 t1 ON cte.CommonId = t1.CommonId
FULL OUTER JOIN @T2 t2 ON cte.CommonId = t2.CommonId