首页 > 解决方案 > SQL Server:基于 3 个表匹配记录

问题描述

我正在尝试匹配三个表之间的记录,两个表是要匹配的数据,第三个表是一个中央表,告诉我应该如何匹配记录。

一个例子会比长篇演讲更清楚:

表格1

Value1  A1  B1  C1
------------------
  0.1   1   b   z
  0.2   4   b   z
  1.1   5   b   z
  1.5   5   c   y
  2.5   7   c   x

表 2

Value2  A2  B2  C2
------------------
  0.5   1   d   z
  0.7   4   d   z
  2.3   7   d   z
  1.7   5   e   y
  1.9   7   e   x

表3

    BL  BR  C
   -----------
     d   b  z
     c   e  x
     c   e  y

一种看待这一点的方式是,A 代表持股,C 代表持有人,B 代表日期。所以表 1 告诉我在某些日期的持股量,表 2 在其他一些日期告诉我相同的情况,最后表 3 告诉我如何比较持股量,例如对于持有人 C = z,我想比较日期 B = d 之间的持股量和日期 B = b(实际上表 1 和表 2 相同)。

所以我寻找的是一个比较馆藏的表格,考虑到创建的馆藏和删除的馆藏。我正在寻找类似的东西:

Value1 A1  B1  C1  BR BL C  A2 B2 C2 Value2
-------------------------------------------
  0.1   1   b   z   b d  z  1   d  z  0.5
  0.2   4   b   z   b d  z  4   d  z  0.7
  1.1   5   b   z   b d  z
                    b d  z  7   d  z  2.3
  1.5   5   c   y   c e  y  5   e  y  1.7
  2.5   7   c   x   c e  x  7   e  x  1.9

所以基本上,只有当 A1 = A2、C1 = C2 和 B1 = BR、B2 = BL 时,记录才会匹配,否则它的一侧或另一侧为空。

我希望这很清楚。我尝试了各种方法(左/右/完全连接)但没有成功。欢迎任何帮助!

谢谢

编辑 添加示例代码。这是 T-SQL。

CREATE TABLE #T1  (Value1 FLOAT, A1 INT, B1 CHAR, C1 CHAR);  
CREATE TABLE #T2 (Value2 FLOAT, A2 INT, B2 CHAR, C2 CHAR);  
CREATE TABLE #T3 (BR CHAR, BL CHAR, C CHAR);  

INSERT INTO #T1  VALUES (0.1, 1, 'b', 'z'), 
                (0.2, 4, 'b', 'z'), 
                (1.1, 5, 'b', 'z'), 
                (1.5, 5, 'c', 'y'), 
                (2.5, 7, 'c', 'x');

INSERT INTO #T2  VALUES (0.5, 1, 'd', 'z'), 
                (0.7, 4, 'd', 'z'), 
                (2.3, 7, 'd', 'z'), 
                (1.7, 5, 'e', 'y'), 
                (1.9, 7, 'e', 'x');

INSERT INTO #T3  VALUES ('b', 'd', 'z'), 
                    ('c', 'e', 'x'),
                    ('c', 'e', 'y');

我试过的示例查询。

SELECT 
    *
FROM #T3 
LEFT JOIN #T1 ON #T1.B1 = #T3.BR AND #T1.C1 = #T3.C
FULL JOIN #T2 ON #T2.B2 = #T3.BL AND #T2.C2 = #T3.C AND #T2.A2 = #T1.A1

这就是我得到的结果。关闭,但我希望 BR、BL 和 C 永远不会为 NULL,因为在那之后我在这些列上有一些逻辑。这些列的最后一行不必为空,它可以与#T3 中的一行匹配。

整个困难在于AND #T2.A2 = #T1.A1:如果存在这样的记录,我希望它匹配,但如果没有,我希望它表现得好像第二个连接是左连接#T2.B2 = #T3.BL AND #T2.C2 = #T3.C

编辑 2 感谢 Marlin Pierce 的帖子,这是一个返回我要查找的结果的请求:

SELECT Value1 A1,  B1,  C1,  BR, BL, C,  A2, B2, C2, Value2
FROM #T3 inner join #T1 on #T1.B1 = #T3.BR AND #T1.C1 = #T3.C
         inner join #T2 on #T2.B2 = #T3.BL AND #T2.C2 = #T3.C AND #T2.A2 = #T1.A1

UNION ALL

SELECT Value1 A1,  B1,  C1,  BR, BL, C,  A2, B2, C2, Value2
FROM #T3 left join #T2 on #T2.B2 = #T3.BL and #T2.C2 = #T3.C
         full join #T1 on #T1.B1 = #T3.BR and #T1.C1 = #T3.C AND #T2.A2 = #T1.A1
WHERE #T1.A1 is NULL

UNION ALL

SELECT Value1 A1,  B1,  C1,  BR, BL, C,  A2, B2, C2, Value2
FROM #T3 left join #T1 on #T1.B1 = #T3.BR and #T1.C1 = #T3.C
         full join #T2 on #T2.B2 = #T3.BL and #T2.C2 = #T3.C AND #T2.A2 = #T1.A1
WHERE #T2.A2 is NULL

但是我想找到一种更有效/更优雅的方式来做到这一点,它存在。

标签: sql-servertsqljoinouter-join

解决方案


我不确定,但我认为这会给你你正在寻找的结果。(你在找什么有点不清楚。)

我不知道是否有更简单的解决方案,但可能没有,因为您正在通过内部连接的规则寻找折叠交叉组合,但您需要外部连接来包含“缺失”记录。

SELECT Value1 A1,  B1,  C1,  BR, BL, C,  A2, B2, C2, Value2
FROM T3 inner join T1 on T1.B1 = T3.BR
        inner join T2 on T2.B2 = T3.BL
WHERE A1 = A2 and C1 = C2

UNION ALL

SELECT Value1 A1,  B1,  C1,  BR, BL, C,  A2, B2, C2, Value2
FROM T3 inner join T1 on T1.B1 = T3.BR
        left outer join T2 on T2.B2 = T3.BL
WHERE T2.B2 is NULL

UNION ALL

SELECT Value1 A1,  B1,  C1,  BR, BL, C,  A2, B2, C2, Value2
FROM T3 inner join T2 on T2.B2 = T3.BL
        left outer join T1 on T1.B1 = T3.BR
WHERE T1.B1 is NULL

推荐阅读