Postgres установить окончательное значение на основе некоторых условий - PullRequest
0 голосов
/ 17 марта 2020

Моя Postgres В таблице есть столбец с именем status, состоящий из завершенных, неисправных или запущенных. Основываясь на этих значениях, я хочу установить конечный результат, если все выполнено, затем окончательный результат = завершен, если произошел сбой, затем результат = сбой, если запущен, и нет неудачной записи, то результат выполняется.

code | status   | parent_code
1    | complete |      3
2    | running  |      3
3    | ----     |

В В приведенной выше таблице для кода = 3 я хочу установить статус на выполнение.

Также, если кто-то может сказать мне, как установить триггер для того же самого, всякий раз, когда происходят изменения, я хочу сохранять значение parent обновленным.

Ответы [ 3 ]

2 голосов
/ 17 марта 2020

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

update the_table tt
   set status = case 
                   when x.failed > 0 then 'failed'
                   when x.running > 0 then 'running'
                   when x.total_rows = x.completed then 'completed'
                end
from (
  select parent_code, 
         count(*) as total_rows,
         count(*) filter (where status = 'running') as running,
         count(*) filter (where status = 'failed') as failed,
         count(*) filter (where status = 'completed') as completed
  from the_table
  where parent_code is not null
  group by parent_code
) x 
where tt.parent_code is null   
  and tt.code = x.parent_code
1 голос
/ 17 марта 2020

Лошадь без имени, ответ - это хорошо (и я проголосовал за нее). Это предложение по упрощению:

update the_table tt
    set status = p.status
    from (select parent_code, 
                 coalesce(max(status) filter (where status = 'failed'),
                          max(status) filter (where status = 'running'),
                          max(status) filter (where status = 'completed')
                         )
           from the_table
           group by parent_code
          ) p 
    where tt.parent_code is null and 
          tt.code = p.parent_code;
0 голосов
/ 17 марта 2020

Оба приведенных выше ответа @a_horse_with_no_name и @Gordon Linoff верны. Здесь я преобразовал его в хранимую процедуру и написал триггер для того же. Для кого-то это может быть полезно.

  1. Написание хранимой процедуры.
  2. Создание триггера.

Написание хранимой процедуры.

CREATE OR REPLACE FUNCTION UpdateStatus()
RETURNS TRIGGER AS $$
BEGIN
update the_table tt
   set status = case 
                   when x.failed > 0 then 'failed'
                   when x.running > 0 then 'running'
                   when x.total_rows = x.completed then 'completed'
                end
from (
  select parent_code, 
         count(*) as total_rows,
         count(*) filter (where device_discovery_status = 'running') as running,
         count(*) filter (where device_discovery_status = 'failed') as failed,
         count(*) filter (where device_discovery_status = 'completed') as completed
  from the_table
  where parent_code is not null
  group by parent_code
) x 
where tt.parent_code is null   
  and tt.code = x.parent_code;
RETURN NULL;
END;
$$ 
LANGUAGE plpgsql;

Создание триггера.

CREATE TRIGGER update_status_on_change
    AFTER UPDATE ON the_table
    FOR EACH ROW
    WHEN (OLD.* IS DISTINCT FROM NEW.*)
    EXECUTE PROCEDURE UpdateStatus();

Таким образом, при каждом изменении статуса update_status_on_change триггер срабатывает и соответственно устанавливает окончательное состояние.

...