Обновить запись из предыдущей строки - PullRequest
0 голосов
/ 06 августа 2020

SQL Server 2008 R2

Есть таблица ниже:

Device       | DateOfSample|  Value
=================================
Pump 1 Starts| 2020-07-07|    0
Pump 1 Starts| 2020-07-08|    32
Pump 1 Starts| 2020-07-09|    30
Pump 1 Starts| 2020-07-10|    5
Pump 1 Starts| 2020-07-11|    29
Pump 1 Starts| 2020-07-12|    0
Pump 1 Starts| 2020-07-13|    57
Pump 1 Starts| 2020-07-14|    50
Pump 1 Starts| 2020-07-15|    0
Pump 1 Starts| 2020-07-16|    52

Мне нужно обновить таблицу значений, чтобы иметь значение предыдущих дней, если оно равно 0, чтобы оно выглядело вот так:

Device       | DateOfSample|  Value
=================================
Pump 1 Starts| 2020-07-07|    0
Pump 1 Starts| 2020-07-08|    32
Pump 1 Starts| 2020-07-09|    30
Pump 1 Starts| 2020-07-10|    5
Pump 1 Starts| 2020-07-11|    29
Pump 1 Starts| 2020-07-12|    29
Pump 1 Starts| 2020-07-13|    57
Pump 1 Starts| 2020-07-14|    50
Pump 1 Starts| 2020-07-15|    50
Pump 1 Starts| 2020-07-16|    52

Я не хочу, чтобы первое значение в таблице менялось, если оно равно 0, но любые другие значения 0 должны быть записаны так же, как и накануне.

Я пытался использовать Update Case, но, похоже, ничего не добился.

UPDATE #MaxValues
    SET Value = CASE
    WHEN m.Value = 0 THEN (
        SELECT m1.Value
        FROM #MaxValues m1
        WHERE m1.DateOfSample = DateAdd (Day, -1, (SELECT m2.DateOfSample FROM #MaxValues m2 WHERE Value = 0)))
    ELSE m.Value
    END
FROM #MaxValues AS m

Все, что я получаю, это ошибка:

Msg 512, уровень 16, состояние 1, процедура sp_PumpStartAvg, строка 156 Подзапрос вернул более одного значения. Это недопустимо, если подзапрос следует за =,! =, <, <=,>,> = Или когда подзапрос используется как выражение.

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

Любой совет приветствуется.

Ответы [ 5 ]

1 голос
/ 06 августа 2020

В SQL Server, подумайте, что самый простой и эффективный подход - это оконная функция и обновляемый CTE:

with cte as (
    select value, lag(value) over(partition by devince order by dateOfSample) lag_value
    from mytable 
)
update cte set value = lag_value
where value = 0 and lag_value is not null
0 голосов
/ 07 августа 2020

Спасибо всем за помощь.

В итоге я решил проблему, построив исходную таблицу по-другому. Тем самым устраняя необходимость решать проблему вообще.

0 голосов
/ 06 августа 2020

Предполагая, что под «предыдущей строкой» вы подразумеваете «предыдущую дату», тогда join является лучшим решением:

update t
    set Value = coalesce(t1.Value, 0)
from t left join
     t tprev
     on tprev.DateofSample = dateadd(day, -1, t.DateofSample);

Если под «предыдущей строкой» вы действительно подразумеваете предыдущую строку, даже если есть пробелы, то решение GMB с использованием lag() - для чего требуется SQL Server 2012 - является лучшим решением.

0 голосов
/ 06 августа 2020

Вы можете найти предыдущую дату с помощью функции DateTime (Datediff). Попробуйте этот запрос, пожалуйста:

Update t2
Set t2.Value=t1.Value
FROM Table t1
left join Table t2
on DATEDIFF(dd,t1.DateofSample,t2.DateofSample)=1
and t2.device=t1.device
and t2.Value=0
0 голосов
/ 06 августа 2020

Попробуйте следующее:

DECLARE @DataSource TABLE
(
    [Device] VARCHAR(16)
   ,[DateOfSample] DATE
   ,[Value] INT
);

INSERT INTO @DataSource ([Device], [DateOfSample], [Value])
VALUES ('Pump 1 Starts', '2020-07-07', 0)
      ,('Pump 1 Starts', '2020-07-08', 32)
      ,('Pump 1 Starts', '2020-07-09', 30)
      ,('Pump 1 Starts', '2020-07-10', 5)
      ,('Pump 1 Starts', '2020-07-11', 29)
      ,('Pump 1 Starts', '2020-07-12', 0)
      ,('Pump 1 Starts', '2020-07-13', 57)
      ,('Pump 1 Starts', '2020-07-14', 50)
      ,('Pump 1 Starts', '2020-07-15', 0)
      ,('Pump 1 Starts', '2020-07-16', 52);

UPDATE DS1
SET [Value] = DS2.[Value]
FROM @DataSource DS1
INNER JOIN @DataSource DS2
    ON DS1.[Device] = DS2.[Device]
    AND DS1.[DateOfSample] = DATEADD(DAY, 1, DS2.[DateOfSample])
WHERe DS1.[Value] = 0


SELECT *
FROM @DataSource
ORDER BY [Device]
        ,[DateOfSample];

введите описание изображения здесь

...