更新中间行

时间:2015-06-26 20:34:51

标签: sql sql-server tsql

嗨我有这样的数据集:

Date                    ID
2015-06-17 15:57:00.000 1
NULL                    2
NULL                    3
NULL                    4
NULL                    5
NULL                    6
2015-06-17 15:58:00.000 7
NULL                    8
NULL                    9
NULL                    10
NULL                    11
NULL                    12
2015-06-17 17:50:04.000 13
NULL                    14
2015-06-17 17:51:00.000 16
NULL                    17
2015-06-17 17:52:03.000 19
NULL                    20
2015-06-17 17:52:04.000 22
NULL                    23
2015-06-17 17:52:04.000 25
NULL                    26
2015-06-17 17:52:04.000 28
NULL                    29

如您所见,它们按顺序(升序),但许多日期为NULL

我想更新NULL条目以获得最接近的先前日期/时间

所以第2行到第6行应该从第1行和第1行获取日期时间 8到12应该从ID 7等获得日期时间

我确信使用单个更新语句可以轻松实现此目的,但我会画一个空白

4 个答案:

答案 0 :(得分:3)

您应该能够使用相关子查询来执行此操作;当我尝试它时,以下查询似乎有效(请参阅下面的小提琴),但请确保备用方便,以防我错了: - )

update t1
set date = (select max(date) from your_table where id <= t1.id and date is not null)
from your_table t1
where t1.date is null

Sample SQL Fiddle

请注意,如果日期不是我认为的顺序日期,这可能会产生一些奇怪的结果。

此外,如果您使用的是版本2012+的SQL Server,那么使用max()函数作为窗口函数(max(date) over (...))是更好的选择。详情见另一个答案。

答案 1 :(得分:2)

你可以在这里有效地使用MAX()OVER()

Update table1 
    set t1.date = t2.date
    From 
          table1 t1
          INNER JOIN (Select id, max(date) over(order by id) date from table1)    t2
          ON t1.id = t2.id

DEMO

作为Quassnoi points out,这取决于日期不减少。

Martin Smith contens这个表述更好

WITH CTE AS (
       Select *, 
              max(Date) over(order by ID) AS newdate 
       from table1) 
UPDATE CTE 
SET Date = newdate

答案 2 :(得分:1)

2012年及以上:

WITH    s AS
        (
        SELECT  id, date,
                COALESCE(
                        LEAD(id) OVER (ORDER BY id),
                        (
                        SELECT  MAX(id) + 1
                        FROM    t
                        )
                ) nid
        FROM    t
        WHERE   date IS NOT NULL
        )
MERGE
INTO    t
USING   s
ON      t.id > s.id
        AND t.id < s.nid
WHEN MATCHED THEN
UPDATE
SET     date = s.date
;

这仍然需要读取整个表两次,但是对于每个记录反复来说,它比一个嵌套循环更有效,特别是如果间隙很大。

早期版本:

UPDATE  m
FROM    mytable m
SET     date =
        (
        SELECT  TOP 1
                date
        FROM    mytable mi
        WHERE   mi.id < m.id
                AND mi.date IS NOT NULL
        ORDER BY
                id DESC
        )
WHERE   date IS NULL

答案 3 :(得分:0)

    Drop Table T1
GO
Create table T1( MyDate DateTime, Id int );

Insert T1 Values
('2015-06-17 15:57:00.000',  1),
(NULL, 2), 
(NULL, 3), 
(NULL, 4), 
(NULL, 5), 
(NULL, 6), 
('2015-06-17 15:58:00.000', 7), 
(NULL, 8), 
(NULL, 9), 
(NULL, 10), 
(NULL, 11), 
(NULL, 12), 
('2015-06-17 17:50:04.000', 13), 
(NULL, 14), 
('2015-06-17 17:51:00.000', 16), 
(NULL, 17), 
('2015-06-17 17:52:03.000', 19), 
(NULL, 20), 
('2015-06-17 17:52:04.000', 22), 
(NULL, 23), 
('2015-06-17 17:52:04.000', 25), 
(NULL, 26), 
('2015-06-17 17:52:04.000', 28), 
(NULL, 29) ;

SELECT 
    A.MyDate,b.LastDate, A.Id
FROM T1 A
CROSS APPLY( 
            Select Top 1 MyDate as LastDate  
            From T1 
            where Id <= A.Id and Mydate is not null
            order by id desc   
            ) B