2015-11-23 32 views
1

我有以下兩個表:SQL情況下,JOIN返回多餘的行

T1

Id  Value 
NULL  A 
NULL  B 
NULL  C 

T2

Id  Value 
1   A 
2   C 
-2  Unmatched 

我想加入價值,使用CASE表達式,t1中的所有行在t2中具有對應的行。對於那些不匹配,我想默認爲不匹配的行(-2)。我的預期產出將是:

t1.Id  t1.Value  t2.Id  t2.Value 
NULL  A   1   A 
NULL  B   -2  Unmatched 
NULL  C   2   C 

但是使用下面的腳本:

WITH t1 
AS 
(
    SELECT NULL AS Id, 
      'A' AS Value 
    UNION ALL 
    SELECT NULL AS Id, 
      'B' AS Value 
    UNION ALL 
    SELECT NULL AS Id, 
      'C' AS Value 
), 
t2 
AS 
(
    SELECT 1 AS Id, 
      'A' AS Value 
    UNION ALL 
    SELECT 2 AS Id, 
      'C' AS Value 
    UNION ALL 
    SELECT -2 AS Id, 
      'Not Matched' AS Value 
) 
SELECT * 
FROM t1 
    LEFT OUTER JOIN t2 
     ON (CASE 
       WHEN t1.Value = t2.Value 
        THEN t2.Id 
       WHEN t1.Value IS NOT NULL 
        THEN -2 
      END) = t2.Id; 

我得到如下結果:

t1.Id  t1.Value  t2.Id  t2.Value 
NULL  A   1   A 
NULL  A   -2  Unmatched 
NULL  B   -2  Unmatched 
NULL  C   2   C 
NULL  C   -2  Unmatched 

我有一個簡單的解決方法,會做什麼,我需要然而我的問題是爲什麼我看起來在我的案例表達式中看到這種行爲?除去第二WHEN產生以下,這幾乎是期望:

t1.Id  t1.Value  t2.Id  t2.Value 
NULL  A   1   A 
NULL  B   NULL  NULL 
NULL  C   2   C 

回答

2

要回答你的問題,每一行即使它有其他比賽-2行相匹配。如果我簡化ON子句,只顯示-2比賽,很明顯:

SELECT * 
FROM t1 
JOIN t2 
    ON CASE WHEN t1.Value IS NOT NULL THEN -2 END = t2.Id; 
+0

是的,因爲t1.Value永遠不能爲null它總是會顯示該行,並t1.Value只是有時等於T2 。值。 – Dijkgraaf

+0

我明白這一點,所有行都滿足IS NOT NULL,但是從CASE上的MSDN「CASE語句順序評估其條件並停止滿足條件滿足的第一個條件」 - 爲什麼它會評估第二個WHEN所有的行? – dbards

+0

當它正在評估的每一行都爲真時,它停止評估CASE語句。下一行開始新鮮。因此'A'行匹配'A',然後一個新行的case語句通過'A'不爲null,因此匹配-2到-2。 – JBrooks

0

由於JBrooks在他的回答中指出,您的WHEN t1.Value IS NOT NULL將永遠是真實的(如t1.Value是從來沒有空這是您的加入的左側)。

完全刪除WHEN,只需在select語句中執行ISNULL或COALESCE。

WITH t1 
AS 
(
    SELECT NULL AS Id, 
      'A' AS Value 
    UNION ALL 
    SELECT NULL AS Id, 
      'B' AS Value 
    UNION ALL 
    SELECT NULL AS Id, 
      'C' AS Value 
), 
t2 
AS 
(
    SELECT 1 AS Id, 
      'A' AS Value 
    UNION ALL 
    SELECT 2 AS Id, 
      'C' AS Value 
    UNION ALL 
    SELECT -2 AS Id, 
      'Not Matched' AS Value 
) 
SELECT t1.id, t1.value, ISNULL(t2.id, -2), ISNULL(t2.value,'Unmatched') 
FROM t1 
    LEFT OUTER JOIN t2 ON t1.value = t2.value 
; 

結果

NULL A 1 A 
NULL B -2 Unmatched 
NULL C 2 C