将子查询的UPDATE记录放入自己的表中

时间:2013-05-28 21:00:09

标签: sql sql-server

我有一张日历表,我正试图用它来处理一些周末和假期问题。

结构很简单:

CREATE TABLE calendar
(
    daterank INT,
    thedate DATE
);

这个想法是每条记录都有一个日期,用于比较目的。非假日工作日有增量日期,周末和假日的日期等于前一个非假日工作日。

为非假日工作日设置daterank比我想象的要容易,但设置周末和假期比我想象的要复杂。

数据的一个子集:

daterank    thedate

881         2013-05-21
882         2013-05-22
883         2013-05-23
884         2013-05-24
NULL        2013-05-25
NULL        2013-05-26
885         2013-05-27
886         2013-05-28
887         2013-05-29
888         2013-05-30
889         2013-05-31
NULL        2013-06-01

在上面的例子中,我想要的是用884(5/24的值)替换5/25和5/26的NULL,用889替换6/1的NULL等等。

什么行不通:

UPDATE calendar c1
SET c1.daterank = (
    SELECT MAX(c2.daterank)
    FROM calendar c2
    WHERE c2.thedate < c1.thedate
    AND c2.daterank IS NOT NULL
)
WHERE daterank IS NULL
;

有什么想法吗?

4 个答案:

答案 0 :(得分:2)

您不得对要更新的表使用别名。

UPDATE calendar 
SET daterank = (
    SELECT MAX(c2.daterank)
    FROM calendar c2
    WHERE c2.thedate < calendar.thedate
    AND c2.daterank IS NOT NULL
)
WHERE daterank IS NULL

答案 1 :(得分:1)

您可以使用以下内容获得结果:

;with cte as
(
  select daterank, thedate
  from calendar
  where daterank is null
) 
update c
set c.daterank = d.daterank
from cte c
cross apply
(
  select top 1 daterank, thedate
  from calendar d
  where d.thedate < c.thedate
    and d.daterank is not null
  order by daterank desc
) d;

请参阅SQL Fiddle with Demo

答案 2 :(得分:0)

你可以使用古怪的更新,我相信这应该有效:

CREATE CLUSTERED INDEX idx_Cal ON calendar (daterank)
GO

DECLARE @Prev_Dt_Rank BIGINT

UPDATE  calendar
SET     daterank =  CASE WHEN daterank IS NULL THEN @Prev_Dt_Rank
                                             ELSE daterank
                                        END                                                                                                                                                         
        ,@Prev_Dt_Rank = daterank
FROM    calendar
WITH (TABLOCKX)
OPTION (MAXDOP 1)
GO

索引是必不可少的,第一个daterank不能为NULL。 有些人对这种奇怪的更新感到厌恶,但在这样的情况下,确保它正常工作是微不足道的。

答案 3 :(得分:0)

这是我的尝试;)

;WITH cte AS
(
  SELECT t.r, t.d
    FROM t 
   WHERE t.r IS NOT NULL
)
, tbl AS
(
  SELECT
    (
      SELECT cte.r
        FROM cte
       WHERE cte.d = (SELECT MAX(sub.d)
                        FROM cte sub
                       WHERE sub.d <= t.d)
    ) AS r,
    t.d
  FROM t 
)

UPDATE t
   SET t.r = tbl.r
  FROM t
  JOIN tbl ON tbl.d = t.d
 WHERE t.r IS NULL

SELECT * FROM t

demo