【发布时间】:2015-04-06 20:02:00
【问题描述】:
我有两个具有相同结构和几乎相同内容的表。主要区别在于一个值列可能与第二个表中的“等效”列不同。最重要的是,一条记录可能会出现在一个表中,但不会出现在另一个表中。
我的桌子:
Table1(idA、valueA、valueB、valueC(可空)、valueX)
Table2(idB、valueA、valueB、valueC(可空)、valueY)
想要的结果:
表3(值A、值B、值C、值X、值Y)
前提条件:
- 'id' 是主键,在两个表中可以不同
- 'valueC' 是唯一可以具有 null 值的列。但是,两个表中的值将相同。
- 如果记录出现在表 1 中但未出现在表 2 中,'valueY' 应为 null
- 如果记录出现在表 2 中但不在表 1 中,'valueX' 应为 null
例子:
表1
1 | 1001 | 2001 | 3001 | 100.0
2 | 1002 | 2002 | 3002 | 95.0
3 | 1003 | 2003 | (空) | 113.0
4 | 1004 | 2004 | 3004 | 75.0
表2
23 | 1001 | 2001 | 3001 | 100.0
24 | 1002 | 2002 | 3002 | 94.0
25 | 1003 | 2003 | (空) | 116.0
26 | 1005 | 2005 | 3005 | 32.0
期望的结果应该是:
表3
1001 | 2001 | 3001 | 100.0 | 100.0
1002 | 2002 | 3002 | 95.0 | 94.0
1003 | 2003 | (空) | 113.0 | 116.0
1004 | 2004 | 3004 | 75.0 | (空)
1005 | 2005 | 3005 | (空) | 32.0
我想我已经想出了一个解决方案,但它非常慢,我不确定这是否真的是最简单的方法。
SELECT valueA, valueB, valueC, valueX, valueY
FROM (
(SELECT t1.valueA, t1.valueB, t1.valueC, t1.valueX, t2.valueY
FROM Table1 t1
LEFT JOIN Table2 t2
ON t1.valueA = t2.valueA
AND t1.valueB = t2.valueB
WHERE t1.valueC = t2.valueC OR t1.valueC IS NULL OR t2.valueC IS NULL)
UNION
(SELECT t2.valueA, t2.valueB, t2.valueC, t1.valueX, t2.valueY
FROM Table2 t2
LEFT JOIN Table1 t1
ON t1.valueA = t2.valueA
AND t1.valueB = t2.valueB
WHERE t1.valueC = t2.valueC OR t1.valueC IS NULL OR t2.valueC IS NULL)
);
我希望有人能想出一个更“优雅”的解决方案。作为旁注,我使用的是 Oracle DB。提前感谢您的时间和帮助!
【问题讨论】:
-
如果两个表之间的 pk 可以不同,你如何匹配记录,即,你如何确定“一个记录可能出现在一个表中,但不能出现在另一个表中”
-
就我的目的而言,匹配基于值 A、B 和 C 的记录就足够了(此处的示例已简化,我的实际表有 7 列匹配)。因此,如果 A、B 和 C 匹配,我们可以假设它是相同的记录。如果其中一个没有,那就是不同的记录。因此,如果您在 table1 中有 ABC 值但在 table2 中没有匹配项,则 table2 中缺少它。
-
然后在 A、B 和 C 列上添加一个键。听起来这可能是一个“自然键”。如果你不能,由于重复而这样做,那么你不能“假设它们是相同的记录”
-
我想您可以将其视为“自然键”,但 C 可以为 null 除外。另一个问题是我不允许更改表,因为这是我的客户定义并在项目中使用的方式。
-
可以添加索引吗?如果是这样,请添加唯一索引。您可以在包含可为空属性的复合键上执行此操作,这将首先防止重复。