2012-09-25 22 views
3

此問題是我的舊問題here的變體。我希望用一個例子來解釋這個問題。所以使用CTE更新上一行值的值

樣本數據
這裏是樣本數據一起工作:

DECLARE @Test TABLE (GID  int,    Seq  int, 
        IsLive bit,    Eff  date, 
        Name  varchar(50),  Salary decimal) 

INSERT INTO @Test VALUES (1, 1, 1, '01-08-2012', 'RTS', NULL) 
INSERT INTO @Test VALUES (1, 2, 0, '01-09-2012', 'RTA', NULL) 
INSERT INTO @Test VALUES (1, 3, 1, '01-10-2012', 'FSA', NULL) 
INSERT INTO @Test VALUES (1, 4, 0, '01-11-2012', NULL, NULL) 
INSERT INTO @Test VALUES (1, 5, 1, '01-12-2012', 'FSA', NULL) 
INSERT INTO @Test VALUES (2, 1, 1, '01-08-2012', 'RTS', NULL) 
INSERT INTO @Test VALUES (2, 2, 0, '01-09-2012', 'RTA', NULL) 
INSERT INTO @Test VALUES (2, 3, 1, '01-10-2012', 'FSA', NULL) 
INSERT INTO @Test VALUES (2, 4, 0, '01-11-2012', 'GSM', NULL) 
INSERT INTO @Test VALUES (2, 5, 1, '01-12-2012', 'FSA', NULL) 
INSERT INTO @Test VALUES (3, 1, 1, '01-01-2012', 'FSA', NULL) 
INSERT INTO @Test VALUES (3, 2, 0, '01-02-2012', NULL, NULL) 
INSERT INTO @Test VALUES (4, 1, 1, '01-01-2012', NULL, NULL) 
INSERT INTO @Test VALUES (4, 2, 0, '01-02-2012', 'FSA', NULL) 
INSERT INTO @Test VALUES (4, 3, 0, '01-03-2012', NULL, NULL) 
INSERT INTO @Test VALUES (5, 1, 0, '01-01-2012', NULL, NULL) 
INSERT INTO @Test VALUES (5, 2, 1, '01-02-2012', 'LSI', NULL) 
INSERT INTO @Test VALUES (5, 3, 0, '01-03-2012', NULL, NULL) 
INSERT INTO @Test VALUES (6, 1, 1, '01-01-2012', NULL, NULL) 
INSERT INTO @Test VALUES (6, 2, 0, '01-02-2012', 'LSI', NULL) 
INSERT INTO @Test VALUES (6, 3, 1, '01-03-2012', NULL, NULL) 

SELECT * FROM @Test 

下面,有兩個樣品結果集。雖然片段展示了插入的一點是要顯示什麼可接受輸出設定將如下所示:

樣本輸出#1
在數據設置如下時,行具有IsLive=0然後從值其列必須在其下方的IsLive=1跳過NULL值的行上寫入相同列的值。在第一行IsLive=0行之前忽略任何IsLive=1行。

INSERT INTO @Test VALUES (1, 1, 1, '01-08-2012', 'RTS', NULL) 
    INSERT INTO @Test VALUES (1, 2, 0, '01-09-2012', 'RTA', NULL) 
    INSERT INTO @Test VALUES (1, 3, 1, '01-10-2012', 'RTA', NULL) 
    INSERT INTO @Test VALUES (1, 4, 0, '01-11-2012', NULL, NULL) 
    INSERT INTO @Test VALUES (1, 5, 1, '01-12-2012', 'RTA', NULL) 
    INSERT INTO @Test VALUES (2, 1, 1, '01-08-2012', 'RTS', NULL) 
    INSERT INTO @Test VALUES (2, 2, 0, '01-09-2012', 'RTA', NULL) 
    INSERT INTO @Test VALUES (2, 3, 1, '01-10-2012', 'RTA', NULL) 
    INSERT INTO @Test VALUES (2, 4, 0, '01-11-2012', 'GSM', NULL) 
    INSERT INTO @Test VALUES (2, 5, 1, '01-12-2012', 'GSM', NULL) 
    INSERT INTO @Test VALUES (3, 1, 1, '01-01-2012', 'FSA', NULL) 
    INSERT INTO @Test VALUES (3, 2, 0, '01-02-2012', NULL, NULL) 
    INSERT INTO @Test VALUES (4, 1, 1, '01-01-2012', NULL, NULL) 
    INSERT INTO @Test VALUES (4, 2, 0, '01-02-2012', 'FSA', NULL) 
    INSERT INTO @Test VALUES (4, 3, 0, '01-03-2012', NULL, NULL) 
    INSERT INTO @Test VALUES (5, 1, 0, '01-01-2012', NULL, NULL) 
    INSERT INTO @Test VALUES (5, 2, 1, '01-02-2012', 'LSI', NULL) 
    INSERT INTO @Test VALUES (5, 3, 0, '01-03-2012', NULL, NULL) 
    INSERT INTO @Test VALUES (6, 1, 1, '01-01-2012', NULL, NULL) 
    INSERT INTO @Test VALUES (6, 2, 0, '01-02-2012', 'LSI', NULL) 
    INSERT INTO @Test VALUES (6, 3, 1, '01-03-2012', 'LSI', NULL) 

    SELECT * FROM @Test AS FakedOutput_1 

樣品輸出#2
在數據設置如下時,行具有IsLive=0然後從它的列的值必須在寫的相同列的值上的行,其中IsLive=1在其下方。具有NULL值的列採用前一行中的值。

INSERT INTO @Test VALUES (1, 1, 1, '01-08-2012', 'RTS', NULL) 
    INSERT INTO @Test VALUES (1, 2, 0, '01-09-2012', 'RTA', NULL) 
    INSERT INTO @Test VALUES (1, 3, 1, '01-10-2012', 'RTA', NULL) 
    -- <- the following row is different from prev 
    INSERT INTO @Test VALUES (1, 4, 0, '01-11-2012', 'RTA', NULL) 
    INSERT INTO @Test VALUES (1, 5, 1, '01-12-2012', 'RTA', NULL) 
    INSERT INTO @Test VALUES (2, 1, 1, '01-08-2012', 'RTS', NULL) 
    INSERT INTO @Test VALUES (2, 2, 0, '01-09-2012', 'RTA', NULL) 
    INSERT INTO @Test VALUES (2, 3, 1, '01-10-2012', 'RTA', NULL) 
    INSERT INTO @Test VALUES (2, 4, 0, '01-11-2012', 'GSM', NULL) 
    INSERT INTO @Test VALUES (2, 5, 1, '01-12-2012', 'GSM', NULL) 
    INSERT INTO @Test VALUES (3, 1, 1, '01-01-2012', 'FSA', NULL) 
    INSERT INTO @Test VALUES (3, 2, 0, '01-02-2012', 'FSA', NULL) 
    INSERT INTO @Test VALUES (4, 1, 1, '01-01-2012', NULL, NULL) 
    INSERT INTO @Test VALUES (4, 2, 0, '01-02-2012', 'FSA', NULL) 
    INSERT INTO @Test VALUES (4, 3, 0, '01-03-2012', 'FSA', NULL) 
    INSERT INTO @Test VALUES (5, 1, 0, '01-01-2012', NULL, NULL) 
    INSERT INTO @Test VALUES (5, 2, 1, '01-02-2012', 'LSI', NULL) 
    INSERT INTO @Test VALUES (5, 3, 0, '01-03-2012', 'LSI', NULL) 
    INSERT INTO @Test VALUES (6, 1, 1, '01-01-2012', NULL, NULL) 
    INSERT INTO @Test VALUES (6, 2, 0, '01-02-2012', 'LSI', NULL) 
    INSERT INTO @Test VALUES (6, 3, 1, '01-03-2012', 'LSI', NULL) 

    SELECT * FROM @Test AS FakedOutput_2 

嘗試性解決方案
以下是我想出了這麼遠,但它沒有我的第一個測試案例(GID=1

;WITH CTE AS ( 
    -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
    SELECT T.GID, T.SEQ, T.IsLive, NULL cGuid, NULL cSEQ, 
      cast(0 as bit) cIsLive, T.Name, T.Salary 
    FROM @Test T 
    JOIN @Test S ON T.GID = S.GID AND T.Seq = S.Seq AND S.IsLive = 0 
    -- - - - - - - 
     UNION ALL 
    -- - - - - - - 
    SELECT t.GID, t.SEQ, T.IsLive, c.GID cGID, c.Seq cSEQ, 
      c.IsLive cIsLive, ISNULL(C.Name, T.Name), 
      ISNULL(t.Salary, c.Salary) 
    FROM CTE c 
    JOIN @Test t ON t.GID  = c.GID AND 
          t.Seq  > c.Seq AND 
          t.IsLive = 1  AND 
          c.IsLive = 0 
    -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
) 
--SELECT * FROM CTE ORDER BY CTE.GID, CTE.Seq 
UPDATE t 
SET  Name = c.Name, Salary = c.Salary 
FROM @Test t 
JOIN CTE c  ON c.GID = t.GID AND c.Seq = t.SEQ 
WHERE C.cIsLive IS NOT NULL 
+0

@Mahmoud:謝謝,剛剛在修復格式化過程。 – KShan

+0

@GilM自從你釘上前一個以後,你可能會想刺穿它! – KShan

+0

我更新了一篇文章,我似乎無法格式化(或者說我不知道​​如何格式化)新添加的測試用例:( – KShan

回答

1

使用APPLY作品測試用例。下面給出了相同的解決方案2

SELECT t1.GID, 
     t1.Seq, 
     t1.IsLive, 
     t1.Eff, 
     CASE WHEN t1.IsLive = 0 THEN COALESCE(t1.Name, t3.Name) ELSE COALESCE(t3.Name, t1.Name) END AS Name, 
     Salary 
FROM @Test T1 
     OUTER APPLY 
     ( SELECT TOP 1 Name 
      FROM @Test T2 
      WHERE T2.GID = T1.GID 
      AND  T2.Seq < T1.Seq 
      AND  t2.IsLive = 0 
      AND  t2.Name IS NOT NULL 
      ORDER BY Seq DESC 
     ) t3 

編輯

只注意到一個UPDATE被要求:

UPDATE @Test 
SET  Name = CASE WHEN t1.IsLive = 0 THEN COALESCE(t1.Name, t3.Name) ELSE COALESCE(t3.Name, t1.Name) END 
FROM @Test T1 
     OUTER APPLY 
     ( SELECT TOP 1 Name 
      FROM @Test T2 
      WHERE T2.GID = T1.GID 
      AND  T2.Seq < T1.Seq 
      AND  t2.IsLive = 0 
      AND  t2.Name IS NOT NULL 
      ORDER BY Seq DESC 
     ) t3 

EDIT 2

我已經改變了稍微在裏面查詢,現在它會試着找到cl osest行有活= 0,名稱不爲空,如果沒有行,其中活= 1(如在GID = 4)將採取最接近的排在那裏的名字不爲空:

UPDATE @Test 
SET  Name = CASE WHEN t1.IsLive = 0 THEN COALESCE(t1.Name, t3.Name) ELSE COALESCE(t3.Name, t1.Name) END 
FROM @Test T1 
     OUTER APPLY 
     ( SELECT TOP 1 Name 
      FROM @Test T2 
      WHERE T2.GID = T1.GID 
      AND  T2.Seq < T1.Seq 
      AND  t2.Name IS NOT NULL 
      ORDER BY t2.IsLive, Seq DESC 
     ) t3 
+0

謝謝!我添加了幾個測試用例,它適用於所有但其中一個(Gid = 3) – KShan

+0

此解決方案需要爲n個coulumns工作(因此最後的Salary列,但我沒有填充它)。我不確定這個解決方案會這樣做。 – KShan

1

它我花了一段時間才意識到這個問題只是我之前發佈的問題的一個小小的變化。離鍵盤只有一段時間讓我看到了答案! @GarethDs也對此做出了貢獻。

;WITH CTE AS ( 
    SELECT T.GID, T.SEQ, T.IsLive, Name, Salary 
    FROM @Test T 
    JOIN (SELECT GID, MIN(Seq) Seq 
       FROM  @Test 
       GROUP BY GID  
      ) S ON T.GID = S.GID AND T.Seq = S.Seq 

    UNION ALL 

    SELECT t.GID, t.SEQ, T.IsLive, 
      CASE WHEN T.IsLive = 0 THEN COALESCE(T.Name, C.Name) 
       ELSE COALESCE(C.Name, T.Name) END, 
      CASE WHEN T.IsLive = 0 THEN COALESCE(T.Salary, C.Salary) 
       ELSE COALESCE(C.Salary, T.Salary) END 
    FROM CTE C 
    JOIN @Test T ON T.GID = C.GID AND T.SEQ = C.SEQ+1 
) 
--SELECT * FROM CTE ORDER BY CTE.GID, CTE.Seq 
UPDATE T 
SET Name = C.Name, 
     Salary = C.Salary 
FROM @Test T 
JOIN CTE C ON C.GID = T.GID AND C.Seq = T.SEQ