2015-02-06 33 views
0

我有兩個具有相同結構和幾乎相同內容的表格。主要區別在於一個值列可能與第二個表中的「等值」列不同。最重要的是,一張表可能出現在一張表中,但另一張沒有。顯示來自兩個不同表格(比較表)的兩列之間的差異

我的表:

表1(IDA,值a,VALUEB,valueC(可爲空),valueX)
表2(IDB,值a,VALUEB,valueC(可爲空),VALUE年)

期望的結果:

表3(值a,VALUEB,valueC,valueX,VALUE年)

前提:

  • 「ID」是主鍵,並且可以在兩個表
  • 「valueC」在不同的是,可以有一個值的唯一的列。但是,兩個表中的值都是相同的。
  • 如果記錄出現在表1,但不是在表2,「VALUE年」應爲
  • 如果記錄出現在表2,但不是在表1,「valueX」應

示例:

表1
1 | 1001 | 2001 | 3001 | 100.0
2 | 1002 | 2002 | 3002 | 95.0
3 | 1003 | 2003 | (null)| 113.0
4 | 1004 | 2004 | 3004 | 75.0

表2
23 | 1001 | 2001 | 3001 | 100.0
24 | 1002 | 2002 | 3002 | 94.0
25 | 1003 | 2003 | (null)| 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 | (null)| 113.0 | 116.0
1004 | 2004 | 3004 | 75.0 | (null)
1005 | 2005 | 3005 | (null)| 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數據庫。預先感謝您的時間和幫助!

+2

如果PK可以在兩個表之間的差異,你怎麼匹配的記錄,即,你怎麼能確定,如果/當「一個記錄可能出現在一個表中,而不是在其他的」 – 2015-02-06 16:07:27

+0

對於我的目的是足以匹配基於值A,B和C的記錄(這裏的示例是簡化的,我的實際表格有7個匹配的列)。所以如果A,B和C匹配,我們可以認爲它是相同的記錄。如果其中一個沒有,這是一個不同的記錄。所以,如果你在table1中有ABC值,但在table2中沒有匹配,那麼它在table2中就沒有了。 – Kratos 2015-02-09 09:48:57

+0

然後在列A,B和C上添加一個鍵。這樣的聲音可能是「自然鍵」。如果你不能,做到這一點是因爲重複,那麼你可以「假設它們是相同的記錄」並不是真的 – 2015-02-09 13:41:31

回答

0

此查詢給出了期望的輸出。我不知道,如果它是更優雅,但更短的肯定;-)

select valueA, valueB, nvl(table1.valueC, table2.valueC) valueC, valueX, valueY 
    from table1 
    full join table2 using (valueA, valueB) 
    order by valueA 

BTW查詢只有4行了,沒有1004 | 2004 | 3004 | 75.0 | (null),可能是你的where應該是:

where t1.valueC = t2.valueC OR t1.valueC IS NULL or t2.valueC IS NULL 

代替

WHERE t1.valueC = t2.valueC OR (t1.valueC IS NULL AND t1.valueC IS NULL) 

重做查詢

select a, b, nvl(t1c, t2c) c, x, y 
    from (
    select nvl(t1.valueA, t2.valueA) a, nvl(t1.valueB, t2.valueB) b, 
     t1.valueC t1c, t2.valueC t2c, valueX x, valueY y 
     from table1 t1 
     full join table2 t2 on (t1.valueA = t2.valueA and t1.valueB = t2.valueB 
      and (t1.valueC = t2.valueC or (t1.valueC is null and t2.valueC is null))) 
     ) 
    order by a, b, c 
+0

我認爲這可能是答案。這絕對比我的查詢短得多,速度快5倍。而且你對我的where子句也是正確的,我認爲我在那裏犯了一個錯誤(我修改了你的更正的問題)。奇怪的是,雖然你的查詢返回6438772記錄,我的返回6879424.我希望這是由於我的查詢中的另一個問題,我目前似乎無法看到。 – Kratos 2015-02-09 11:24:29

+0

由於對C值的誤解而出現差異。你在主文章中的最後評論改變了一些事情。所以我修改了查詢,我認爲它適用於所有條件。如果向table1和(27,1006,2006,null,201)添加行(5,1006,2006,3006,101)到table2,它在列valueX和valueY中會產生不同的結果,但我認爲您不能從非匹配行取這些值。 – 2015-02-09 19:33:32

+0

此外,如果您現在將table2中增加的行中的valueC從null更改爲3007,那麼我的查詢會在結果中給出7行,即您的-5行。我這樣做是因爲如果行不匹配ABC,那麼我們列出它們都沒有加入。 – 2015-02-09 19:42:55

0

創建表C作爲(SELECT * FROM表負SELECT * FROM表B)聯盟(SELECT * FROM表B減去SELECT * FROM表A)

+0

謝謝,但不幸的是,這不起作用,因爲它還加入了ID和valueX和valueY列,這些列在每個表中可能有不同的值。它也不會並列最後兩列,這正是我所需要的。 – Kratos 2015-02-09 09:36:11

+0

如果您使用我的查詢但選擇較少的列? – 2015-02-09 09:37:30