2015-04-14 16 views
0

因此,我有兩個表T1和T2,其中T1中包含具有所有唯一值的主鍵列「A」,T2具有外鍵「A 「 如下所示。SQL Server - 使用FROM和JOIN更新不考慮滿足JOIN條件的所有行

T1 
--- 
A ConditionMet 
1 0 
2 0 

T2 
--- 
A B  C 
1 10 5 
1 20 20 
2 10 10 
2 30 0 

現在,我想更新表T1的「ConditionMet」欄爲「1」,每當在T2列B的值等於科拉姆的C值(用於所述的一個具體的值)。我的更新查詢類似下面

UPDATE t1 
SET 
t1.ConditionMet = 
    (CASE WHEN t1.ConditionMet = 0 AND t2.B = T2.C THEN 1 END) 
FROM 
    T1 t1 
INNER JOIN T2 t2 
WHERE 
    t1.A = t2.A 

這裏我的問題是,它不是通過T2的所有行循環,但其經歷的第一條記錄爲「A」的值。假設如果我們在T1中取值「1」,它將只看第一行(1 10 5),而不是在T2的第二行(1 20 20)。請幫我理解這個查詢有什麼問題。提前致謝!!

回答

0

試試這個....

UPDATE t1 
SET 
t1.ConditionMet = CASE WHEN t1.ConditionMet = 0 AND t2.B = T2.C 
         THEN 1 
        END  
FROM T1 t1 
INNER JOIN T2 t2 ON t1.A = t2.A 
WHERE NOT EXISTS (SELECT 1 
        FROM T2 
        WHERE t1.A = A 
        AND B <> C) 
0

的問題是,當它符合這兩個條件,你不能保證它的更新將去年發生的順序。這應該做你需要的:

UPDATE t1 
SET 
    t1.ConditionMet = CASE WHEN T2.a IS NULL THEN 0 ELSE 1 END 
FROM 
    T1 t1 
LEFT JOIN T2 t2 
WHERE 
    t1.A = t2.A 
    and t2.B = t2.C 
0

問題是你期待第一,第二或最後的結果,但沒有定義順序。爲什麼應該A = 1的行,其中B = 10是第一個,B = 20是第二個?它實際上是SQL Server最後一次堅持的更新,但即使如此,你也無法修復你的查詢,只需要一個ORDER BY

你需要編寫一個完全確定性的查詢,也就是說寫一個選擇每行只更新1行,這可以可靠地用作更新。我認爲我不會像雨果·科內利斯那樣呼籲UPDATE...FROM被棄用,但是如果你不被它發現,你需要了解它。

所以,如果你正在尋找那裏是在T2至少一排,其中B = C,那麼我會用更新T1行:

SELECT T1.A, T1.ConditionMet, NewConditionMet = ISNULL(T2.NewConditionMet, 0) 
FROM T1 
     OUTER APPLY 
     ( SELECT TOP 1 NewConditionMet = 1 
      FROM T2 
      WHERE T2.A = T1.A 
      AND  T2.B = T2.C 
     ) AS T2; 

爲您的樣品數據這將返回

A ConditionMet NewConditionMet 
1 0    1 
2 0    1 

所有,那麼你需要做的就是調整你的SELECTUPDATE

UPDATE T1 
SET  ConditionMet = CASE WHEN T1.ConditionMet = 0 THEN ISNULL(T2.NewConditionMet, 0) END 
FROM T1 
     OUTER APPLY 
     ( SELECT TOP 1 NewConditionMet = 1 
      FROM T2 
      WHERE T2.A = T1.A 
      AND  T2.B = T2.C 
     ) AS T2; 

N.B.這是一個非常難得的機會時,我認爲這是正常使用TOP沒有ORDER BY,因爲我只返回一個恆定值的99%的時間是不行的使用TOP沒有ORDER BY


工作示例

DECLARE @T1 TABLE (A INT, ConditionMet BIT); 
DECLARE @T2 TABLE (A INT, B INT, C INT); 
INSERT @T1 VALUES (1, 0), (2, 0), (3, 0), (4, 1); 
INSERT @T2 VALUES (1, 10, 5), (1, 20, 20), (2, 10, 10), (2, 30, 0), (3, 0, 1), (4, 0, 0); 

SELECT * FROM @T1; 

UPDATE T1 
SET  ConditionMet = CASE WHEN T1.ConditionMet = 0 THEN ISNULL(T2.NewConditionMet, 0) END 
FROM @T1 AS T1 
     OUTER APPLY 
     ( SELECT TOP 1 NewConditionMet = 1 
      FROM @T2 AS T2 
      WHERE T2.A = T1.A 
      AND  T2.B = T2.C 
     ) AS T2; 

SELECT * FROM @T1; 
+0

可能我沒有完整的要求。我在T2中有另一列,它表示「運算符」,它可以是「AND」,「OR」或「NULL」。所以,例如,它可能有一個說T2.B(10)= T2.C(5)「AND」T2.B(20)= T2.C(20)的條件。所以,我無法跳過所有行的循環。我可以使用「WHILE」循環來實現這一目標,但希望與像你這樣的專家一起檢查,看看我能否避免這種情況。提前致謝!! – Praveen