ОБНОВЛЕНИЕ, чтобы вычесть время простоя в час - PullRequest
0 голосов
/ 18 апреля 2020

У меня есть 2 таблицы.

Таблица dummy:

dummy table

и таблица down_event:

down_event table

availability_time в таблице dummy в диапазоне от 00:00:00 до 23:00:00. Каждое down_duration_sec в таблице down_event должно быть вычтено из duration_sec в соответствующей строке таблицы dummy. Событие, происходящее в down_time 03:59:59, применяется только к строке с availability_time 03:00:00 в таблице dummy.

В приведенном выше примере показаны только строки для 2020-02-25, но может быть много дат для одного и того же terminal_id.

Чтобы быть понятным, предположим, что эти строки в таблице dummy :

terminal_id    availability_date   availability_time   duration_sec
___________    _________________   _________________   ____________
02262261       2020-02-25          00:00:00            3600
02262261       2020-02-25          01:00:00            3600
02262261       2020-02-25          02:00:00            3600
02262261       2020-02-25          03:00:00            3600

Для события, происходящего в дату 2020-02-25 в момент 1:43:23 с down_duration_sec, равным 10 секундам, таблица dummy должна быть обновлена ​​до:

terminal_id    availability_date   availability_time   duration_sec
___________    _________________   _________________   ____________
02262261       2020-02-25          00:00:00            3600
02262261       2020-02-25          01:00:00            3590
02262261       2020-02-25          02:00:00            3600
02262261       2020-02-25          03:00:00            3600

Пока что это мой код запроса:

    UPDATE dashboard.dummy 
SET duration_sec = 3600 - t.down_duration_sec
FROM (  
    SELECT down_duration_sec
    FROM dashboard.down_event 
    WHERE terminal_id IN (SELECT terminal_id FROM dashboard.dummy)
    GROUP BY down_duration_sec
) t 
WHERE t.terminal_id = dashboard.dummy.terminal_id
AND availability_date IN (
    SELECT down_date 
    FROM dashboard.down_event 
    WHERE down_date IN ( SELECT availability_date FROM dashboard.dummy)
)

Этот запрос работает и смог заполнить значения Terminal_id, Availability_Date и Availability_time.

Но как только я добавлю этот код для вычитания duration_sec:

AND availability_time IN(
    SELECT terminal_id, down_time
    FROM dashboard.down_event 
    WHERE down_time between
    (
        SELECT terminal_id, availability_time 
        FROM dashboard.dummy 
        WHERE terminal_id IN (SELECT terminal_id FROM dashboard.down_event)
        GROUP BY terminal_id, availability_time
    ) 
    AND
    (
        SELECT availability_time + interval '1 hour'
        FROM dashboard.dummy
        WHERE terminal_id IN (SELECT terminal_id FROM dashboard.down_event)
        GROUP BY availability_time
    )
)

.. Я получаю ошибку:

подзапрос должен возвращать только один столбец

Как я правильно понял вычитание?

Ответы [ 3 ]

1 голос
/ 20 апреля 2020

Предполагая, что все столбцы равны NOT NULL.

UPDATE dashboard.dummy d
SET    duration_sec = 3600 - t.sum_down
FROM  (
   SELECT terminal_id, down_date, date_trunc('hour', down_time) AS down_time
        , sum(down_duration_sec) AS sum_down
   FROM   dashboard.down_event 
   GROUP  BY 1, 2, 3
   ) t
WHERE  (t.terminal_id, t.down_date        , t.down_time)
     = (d.terminal_id, d.availability_date, d.availability_time)

В подзапросе t, агрегируйте несколько простоев в час (если это возможно?) После усечения до часа с date_trunc() . Затем присоединитесь к нему в предложении FROM. Это только обновляет строки в таблице dummy, которые на самом деле требуют обновления (должно быть очень мало) - в отличие от подвыбора, показанного Джорджем, который обновляет каждую строку (много пустые обновления). Значительно дешевле. См .:

Выражение date_trunc('hour', down_time) создает interval , но сравнение с time все еще работает.

В сторону: кажется странным вычитать время простоя из начального часа вместо фактически затронутых часов.

0 голосов
/ 20 апреля 2020

Спасибо всем за ответы.

Я исправил эту проблему с помощью этого запроса:

UPDATE dashboard.dummy 
SET duration_sec = 3600 - t.down_duration_sec
FROM (  
    SELECT down_duration_sec, down_date, terminal_id, down_time
    FROM dashboard.down_event 
    WHERE terminal_id IN (SELECT terminal_id FROM dashboard.dummy)
    GROUP BY down_duration_sec, down_date, terminal_id, down_time
) t 
WHERE t.terminal_id = dashboard.dummy.terminal_id
AND dashboard.dummy.availability_date = t.down_date
AND t.down_time BETWEEN dashboard.dummy.availability_time AND dashboard.dummy.availability_time + interval '1 hour'

Я просто использовал BETWEEN AND запроса.

0 голосов
/ 19 апреля 2020

Самый простой способ сделать это с помощью подвыбора в операторе обновления, например:

update dummy d set duration_sec = coalesce( 
  (select 3600 - sum(de.down_duration_sec)
   from down_event de
   where date_trunc('hour', de.down_date + de.down_time) = date_trunc('hour',d.availability_date + d.availability_time)
    and d.terminal_id = de.terminal_id
 ),3600) ;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...