根据邻居更新NULL值

时间:2017-10-25 16:41:06

标签: sql sql-server tsql

我有一张表MyModel,如下所示:

ID | Creation
---|-----------
 1 | 2017-01-01
 2 | NULL
 3 | NULL
 4 | 2017-01-09
 5 | NULL

等等。

我需要为Creation提供值NULL,但是......

每行的Creation需要大于其前一行。

所以以下查询对我不起作用

update MyModel
set Creation = getdate()
where Creation is null

因为它会破坏规则。

结果应该是

ID | Creation
---|-----------
 1 | 2017-01-01
 2 | 2017-01-02
 3 | 2017-01-03
 4 | 2017-01-09
 5 | 2017-01-10
  

如果没有足够的日子在两个值之间有唯一日期怎么办?

如果Creationdatetime,则始终会插入有效的datetime。记录之间的差异总是大于~30秒。

  

如果现有值不符合规定怎么办?

它们已经有序了。订单基于ID

3 个答案:

答案 0 :(得分:1)

如果差距不超过从差距开始和结束的天数差异,这是一种方法。

declare @table table (ID int, Creation datetime)
insert into @table
values
(1,'2017-01-01'),
(2,NULL),
(3,NULL),
(4,'2017-01-09'),
(5,null),
(6,'2017-01-11'),
(7,null)

update t
set t.Creation = isnull(dateadd(day,(t2.id - t.ID) * -1,t2.creation),getdate())
from @table t
left join @table t2 on t2.ID > t.ID and t2.Creation is not null
where t.Creation is  null

select * from @table

<强>返回

+----+-------------------------+
| ID |        Creation         |
+----+-------------------------+
|  1 | 2017-01-01 00:00:00.000 |
|  2 | 2017-01-07 00:00:00.000 |
|  3 | 2017-01-08 00:00:00.000 |
|  4 | 2017-01-09 00:00:00.000 |
|  5 | 2017-01-10 00:00:00.000 |
|  6 | 2017-01-11 00:00:00.000 |
|  7 | 2017-10-25 11:58:56.353 |
+----+-------------------------+

答案 1 :(得分:1)

使用common table expression row_number()

;with cte as (
  select *
    , rn = row_number() over (order by id)
  from mymodel
)
update cte
  set Creation = dateadd(day,cte.rn-x.rn,x.Creation)
from cte 
  cross apply (
    select top 1 *
    from cte i
    where i.creation is not null
      and i.id < cte.id
    order by i.id desc
    ) x
where cte.creation is null;

select * 
from mymodel;

rextester演示:http://rextester.com/WAA44339

返回:

+----+------------+
| id |  Creation  |
+----+------------+
|  1 | 2017-01-01 |
|  2 | 2017-01-02 |
|  3 | 2017-01-03 |
|  4 | 2017-01-09 |
|  5 | 2017-01-10 |
+----+------------+

答案 2 :(得分:-2)

你可以使用有用的光标,在那里你可以比较两个值并轻松更新值 尝试下面的事情

declare stageCursor cursor scroll for 
    select name, startdate, enddate from staging;

declare @name varchar(20), 
        @startdate datetime, 
        @enddate datetime;

open stageCursor
fetch next from stageCursor into @name, @startdate, @enddate
while @@fetch_status = 0 begin
    update operations set o.enddate = dateadd(d, -1, s.startdate) 
    where name = @name --does this need to be restricted to just the latest operations row somehow?

    insert operations (name, startdate, enddate)
    values (@name, @startdate, @enddate);

    fetch next from stageCursor into @name, @startdate, @enddate
end

close stageCursor
deallocate stageCursor

truncate table staging