如何使用下一行中的第一个非零值更新零?

时间:2017-12-19 06:33:46

标签: sql sql-server

如何使用col2中的下一个非零值更新零?

例如 - 我需要使用值2更新col2中的前3行。同样,我需要在2之后接下来的两个值更新为3(对于RN 5,6)

基本上,在每个尾随零之后,如果存在非零,则应该在上面的尾随零中更新它。 如何使用loopsprocedures

执行此操作

enter image description here

4 个答案:

答案 0 :(得分:4)

以下是对此的简单查询,您可以使用OUTER APPLY

来实现此目的
CREATE TABLE #tmp(rn INT IDENTITY(1,1), col1 VARCHAR(50), col2 INT, col3 DATE)
INSERT INTO #tmp VALUES 
('ABC', 0, '2017-01-01'),
('ABC', 0, '2017-01-01'),
('ABC', 0, '2017-01-01'),
('ABC', 2, '2017-01-01'),
('ABC', 0, '2014-02-01'),
('ABC', 0, '2013-02-01'),
('ABC', 3, '2013-01-01'),
('ABC', 0, '2017-01-01'),
('ABC', 0, '2017-01-01'),
('ABC', 0, '2017-01-01'),
('ABC', 0, '2017-01-01'),
('ABC', 7, '2017-01-01')


UPDATE t SET t.col2 = t2.col2
FROM #tmp t
OUTER APPLY(SELECT TOP 1 col2 FROM #tmp WHERE rn >= t.rn AND col2 > 0) t2

输出

rn  col1    col2    col3
1   ABC     2       2017-01-01
2   ABC     2       2017-01-01
3   ABC     2       2017-01-01
4   ABC     2       2017-01-01
5   ABC     3       2014-02-01
6   ABC     3       2013-02-01
7   ABC     3       2013-01-01
8   ABC     7       2017-01-01
9   ABC     7       2017-01-01
10  ABC     7       2017-01-01
11  ABC     7       2017-01-01
12  ABC     7       2017-01-01

答案 1 :(得分:3)

试试这个

DECLARE @T TABLE
(
    RN INT IDENTITY(1,1),
    COL1 VARCHAR(20),
    COL2 INT,
    COL3 DATE,
    COL2_NEW INT NULL
)
INSERT INTO @T(COL1,COL2,COL3)
VALUES('ABC',0,'1/1/2017'),
('ABC',0,'01/01/2017'),
('ABC',0,'01/01/2017'),
('ABC',2,'01/01/2017'),
('ABC',0,'01/01/2017'),
('ABC',0,'01/01/2017'),
('ABC',3,'01/01/2014'),
('ABC',0,'01/01/2017')

;WITH CTE
AS
(
    SELECT
        SeqNo = ROW_NUMBER() OVER(PARTITION BY T1.RN ORDER BY T1.RN,T2.RN),
        T1.RN,
        T2RN = T2.RN,
        T2.COL2
        FROM @T T1
            INNER JOIN @T t2
                ON T1.COL1 = T2.COL1    
                    AND T1.COL2 = 0
                    AND T2.COL2 > 0
                    AND T1.RN < T2.RN
)
UPDATE @T
    SET 
        COL2_NEW = CTE.COL2
    FROM CTE
        INNER JOIN @T T
            ON T.RN = CTE.RN
        WHERE CTE.SeqNo = 1

SELECT
    *
    FROM @T

答案 2 :(得分:2)

假设RN是我们确定列顺序的列:

UPDATE t
SET col2 = t2.col2
FROM
    table t
        inner join
    table t2
        on
            t.rn < t2.rn and
            t2.col2 != 0
        left join
   table t_anti
       on
           t.rn < t_anti.rn and
           t_anti.rn < t2.rn and
           t_anti.col2 != 0
where
    t.col2 = 0 and
    t_anti.rn is null

基本上,我们基于找到具有非零值的后一行将表连接到自身。然后,我们执行进一步的连接,尝试为后一行找到“更好”的匹配。只有当该加入失败时(null子句中的最终where检查),我们才知道我们已找到t2中的最佳匹配。

答案 3 :(得分:1)

这是一个展示概念的快速脚本。对于每一行,找到值为非零的下一个RN,然后将该值更新为该RN的值。

CREATE TABLE #tt(RN INT IDENTITY(1,1) PRIMARY KEY, val INT);
INSERT INTO #tt(val)VALUES(0),(0),(0),(2),(0),(0),(3),(0);
SELECT * FROM #tt;

UPDATE
    #tt
SET
    val=ISNULL((SELECT val FROM #tt AS r WHERE r.RN=mrn.RN),0)
FROM
    #tt AS o
    CROSS APPLY (
        SELECT
            RN=MIN(RN)
        FROM
            #tt AS i
        WHERE
            i.val<>0 AND i.RN>=o.RN
    ) AS mrn;

SELECT * FROM #tt;

DROP TABLE #tt;