2012-02-17 57 views
1

我繼承一個表具有以下結構:CTE可以用來更新通行證嗎?

rowID rn userID Data1 Data2 Data3 
----- -- ------ ----- ---- ---- 
1  1 1  A  null 123 
2  2 1  B  111 null 
3  1 2  C  222 333 
4  2 2  D  null null 
5  3 2  E  111 null 
6  1 3  F  333 222 

第一研究倫理委員會(rn=1)需要被插入,而其餘的(rn <>1)需要更新插入(順序地)。我可以很容易地插入,使用where rn = 1並檢查是否存在用戶標識。

我的問題是,我需要現在使用rn <>1順序更新所有recs,以便用戶表反映最新狀態。也就是說,更新後的用戶表應該是這樣的:

rowID userID Data1 Data2 Data3 
----- ------ ----- ----- ----- 
1  1  B  111 123 
2  2  E  111 333 
3  3  F  333 222 

我的想法是寫一個CTE,其中每個「通」將抓住所有的區域經濟共同體,其中RN = 2,則RN = 3,則RN = 4 ....直到我沒有更多的處理。這樣,我可以套上更新。

這是可能的(或者我應該使用do-while)嗎?如果是這樣,我需要遞歸還是「常規」CTE?

這裏是我的嘗試:

;with my_cte (rowID, rn, userID, Data1, Data2, Data3, val) As 
(
    SELECT rowID, rn, userID, Data1, Data2, Data3, val 
    from @MyTempTable x 
    where rn =1 

     UNION ALL 

    SELECT rowID, rn, userID, Data1, Data2, Data3, b.val +1 
    from @MyTempTable y 
    INNER JOIN 
     my_cte b 
    ON y.userID = b.userID 
    WHERE y.rn = b.val +1 

) 
UPDATE userTable 
SET 
    [Data1] = COALESCE(c.Data1, [Data1]) 
    ,[Data2]= COALESCE(c.Data2, [Data2]) 
    ,[Data3]= COALESCE(c.Data3, [Data3]) 
From @MyTempTable c 
JOIN 
    ( SELECT user_id 
     FROM my_cte 
     WHERE rn<>1 
    ) b 
ON b.user_id = c.user_id 
WHERE 
    EXISTS 
     ( Select userID 
      from userTable q 
      Where q.userId = b.userId 
     ) 

我不能得到這個工作,它看起來像只有第一行更新。有什麼想法嗎?我是CTE的小菜。更重要的是,我想知道CTE究竟在做什麼...甚至有可能讓更新以「通行證」運行?

+0

不應該'Data1'爲'userID' 1是** **乙和你當前最大的是'rn'? – 2012-02-17 07:18:55

+0

@Lieven,你是對的。我編輯了原文。我不知道會發生什麼。目前這個數字已經達到了19,而且我確信我可以走得更高。 – user991945 2012-02-17 07:23:54

回答

1

正在關注CTE返回給定輸出的給定輸入。您可以使用這些結果作爲將記錄插入另一個表的起點。

它的要點是

  • 使用遞歸CTE,從所有行rn=1
  • 在遞歸部分,從遞歸部分中選擇Data1-3(如果可用),否則保留現有值(COALESCE)。該CTE的結果現在是你的最終值+初始值,其中rn=1
  • 添加ROW_NUMBER每個userIDORDER DESC現有rn。這可確保最新的值得到rownumber 1.
  • 最後選擇所有與rownumber 1並根據您的最終結果添加另一個rownumber。

SQL語句

;WITH q AS (
    SELECT rn 
      , UserID 
      , Data1 
      , Data2 
      , Data3 
    FROM Inherited 
    WHERE rn = 1 
    UNION ALL 
    SELECT i.rn 
      , i.UserID 
      , COALESCE(i.Data1, q.Data1) 
      , COALESCE(i.Data2, q.Data2) 
      , COALESCE(i.Data3, q.Data3) 
    FROM q 
      INNER JOIN Inherited i ON i.rn = q.rn+1 AND i.userID = q.userID 
) 
SELECT rn = ROW_NUMBER() OVER (ORDER BY userID) 
     , * 
FROM (
      SELECT UserID 
        , Data1 
        , Data2 
        , Data3 
        , rn = ROW_NUMBER() OVER (PARTITION BY UserID ORDER BY rn DESC) 
      FROM q 

     ) t 
WHERE rn = 1       

測試腳本

;WITH Inherited (rowID, rn, userID, Data1, Data2, Data3) AS (
    SELECT * FROM (VALUES 
    (1, 1, 1, 'A', null, '123') 
    , (2, 2, 1, 'B', '111', null) 
    , (3, 1, 2, 'C', '222', '333') 
    , (4, 2, 2, 'D', null, null) 
    , (5, 3, 2, 'E', '111', null) 
    , (6, 1, 3, 'F', '333', '222') 
) a (b, c, d, e, f, g) 
) 
, q AS (
    SELECT rn 
      , UserID 
      , Data1 
      , Data2 
      , Data3 
    FROM Inherited 
    WHERE rn = 1 
    UNION ALL 
    SELECT i.rn 
      , i.UserID 
      , COALESCE(i.Data1, q.Data1) 
      , COALESCE(i.Data2, q.Data2) 
      , COALESCE(i.Data3, q.Data3) 
    FROM q 
      INNER JOIN Inherited i ON i.rn = q.rn+1 AND i.userID = q.userID 
) 
SELECT rn = ROW_NUMBER() OVER (ORDER BY userID) 
     , * 
FROM (
      SELECT UserID 
        , Data1 
        , Data2 
        , Data3 
        , rn = ROW_NUMBER() OVER (PARTITION BY UserID ORDER BY rn DESC) 
      FROM q 

     ) t 
WHERE rn = 1       
+0

非常酷,它的工作原理。我也認爲我理解它:在第一次傳球中,你有錨(rn = 1)。然後q自己和自己聯合在下一個記錄(rn + 1)上。這使它可以合併數據。我們繼續前進直到rn + 1條件失敗。這給了我們一組順序合併的行,並且我們用最新的行輸出用戶表。我有嗎? (順便說一句,我很喜歡這個!) – user991945 2012-02-17 17:05:36

+0

@ user991945 - 你已經說明了我比更好。 – 2012-02-17 17:20:03

相關問題