Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/sql-server-2008/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 使用CTE从上一行值更新值_Sql_Sql Server 2008_Tsql - Fatal编程技术网

Sql 使用CTE从上一行值更新值

Sql 使用CTE从上一行值更新值,sql,sql-server-2008,tsql,Sql,Sql Server 2008,Tsql,这个问题是我以前问题的一个变体。我希望用一个例子来解释这个问题。所以 样本数据 以下是要使用的示例数据: DECLARE @Test TABLE (GID int, Seq int, IsLive bit, Eff date, Name varchar(50), Salary decimal) INSERT I

这个问题是我以前问题的一个变体。我希望用一个例子来解释这个问题。所以

样本数据 以下是要使用的示例数据:

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的行中相同列的值,跳过空值。忽略第一行IsLive=0之前的任何IsLive=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
使用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
编辑2

我在apply中稍微修改了查询,现在它将尝试查找最近的行,其中live=0且名称不为null,如果没有live=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

我花了一段时间才意识到,这个问题只是我先前发布的问题的一个小变化。离开键盘一段时间,我就看到了答案@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

@马哈茂德:谢谢,我正在修改格式。@GilM你可能想试试这个,因为你已经搞定了上一个!我在更新帖子时弄得有点乱,我似乎无法格式化,或者更确切地说,我不知道如何格式化新添加的测试用例:谢谢!我又添加了几个测试用例。它适用于除一个Gid=3之外的所有人,因此此解决方案需要适用于n个列,因此最后是Salary列,但我还没有填充它。我不确定这个解决方案是否能做到这一点。
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
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
;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