2013-05-28 5 views
3

У меня есть таблица календаря, которую я пытаюсь использовать для решения некоторых выходных и праздничных вопросов.Запись UPDATE с подзапросом в собственный стол

Структура проста:

CREATE TABLE calendar 
(
    daterank INT, 
    thedate DATE 
); 

Идея заключается в том, что каждая запись имеет daterank, который используется для целей сравнения. Нерабочие будни имеют инкрементные датчанты, выходные и праздничные дни, у которых есть бонус, равный непосредственно предшествовавшему празднику в будние дни.

Установка 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 

То, что я хочу, в приведенном выше случае, заменить NULLs для 5/25 и 5/26 с 884 (значение для 5/24), нулевая для 6/1 с 889 и т.д.

Что не работает:

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 
; 

Есть идеи?

+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 
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. У некоторых есть отвращение к изворотливому обновлению, но в такой ситуации тривиально, чтобы он работал правильно.

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

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

Смежные вопросы