3

この質問は、私の以前の質問hereのバリエーションです。例を使って問題を説明したいと思います。そう

サンプル データ
使用するサンプル データは次のとおりです。

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

以下は、2 つのサンプル結果セットです。スニペットは挿入を示していますが、ポイントは、許容可能な出力セットがどのように見えるかを示すことです。

サンプル出力 #1
以下のデータ セットでは、行に次の値が含まIsLive=0れている場合、その列の値は行の同じ列の値を上書きする必要があり、そのIsLive=1下では NULL 値をスキップします。IsLive=1最初の行より前の行は無視しますIsLive=0

    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
4

2 に答える 2

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
于 2012-09-26T10:20:09.587 に答える
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

編集2

適用内のクエリを少し変更しました。ライブ = 0 で名前が null でない最も近い行を見つけようとします。ライブ = 1 の行がない場合 (GID = 4 のように)、名前が null でない最も近い行:

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
于 2012-09-25T15:10:00.603 に答える