Рекомендации по сложному SQL-запросу для набора данных BIRT - PullRequest
0 голосов
/ 17 февраля 2011

У меня есть следующая (упрощенная) таблица базы данных PostgreSQL, содержащая информацию об обслуживании, выполняемом на определенном устройстве:

id bigint NOT NULL,
"time" timestamp(0) with time zone,
action_name text NOT NULL,
action_info text NOT NULL DEFAULT ''::text,

Поле action_name может иметь четыре представляющих интерес значения:

MAINTENANCE_START
DEVICE_DEFECT
DEVICE_REPAIRED
MAINTENANCE_STOP
<other (irrelevant) values>

Я должен сделать отчет BIRT, используя информацию из этой таблицы.У меня должна быть запись в таблице каждый раз, когда встречается действие MAINTENANCE_STOP.Если между этим действием MAINTENANCE_STOP и соответствующим ему действием MAINTENANCE_START (должно быть действие MAINTENANCE_START с максимальным значением «time», меньшим, чем у действия MAINTENANCE_STOP), я сталкиваюсь с действием DEVICE_DEFECT или DEVICE_REPAIRED, я должен написать в ячейке таблицы строку «Deviceнедоступно ", иначе я должен написать" Устройство доступно ".

Кроме того, я должен вычислить продолжительность обслуживания как разницу во времени между действием MAINTENANCE_STOP и действием MAINTENANCE_START.

I сначалапопытался сделать это в запросе SQL, но теперь я не уверен, что это возможно.Какой подход вы рекомендуете?

1 Ответ

1 голос
/ 19 февраля 2011

Мой рабочий фрагмент:

CREATE TABLE "log"
(
  id bigint NOT NULL,
  time timestamp(0) with time zone,
  action_name text NOT NULL,
  action_info text NOT NULL DEFAULT ''::text
);

insert into log(id,time,action_name,action_info) values ( 1, '2011-01-01', 'MAINTENANCE_START', 'maintenance01start');
insert into log(id,time,action_name,action_info) values ( 2, '2011-02-01', 'MAINTENANCE_START', 'maintenance02start');
insert into log(id,time,action_name,action_info) values ( 3, '2011-03-01', 'MAINTENANCE_START', 'maintenance03start');
insert into log(id,time,action_name,action_info) values ( 4, '2011-04-01', 'MAINTENANCE_START', 'maintenance04start');
insert into log(id,time,action_name,action_info) values ( 5, '2011-01-10', 'MAINTENANCE_STOP', 'maintenance01stop');
insert into log(id,time,action_name,action_info) values ( 6, '2011-02-10', 'MAINTENANCE_STOP', 'maintenance02stop');
insert into log(id,time,action_name,action_info) values ( 7, '2011-03-10', 'MAINTENANCE_STOP', 'maintenance03stop');
--insert into log(id,time,action_name,action_info) values ( 8, '2011-04-10', 'MAINTENANCE_STOP', 'maintenance04stop');
insert into log(id,time,action_name,action_info) values ( 9, '2011-02-05', 'DEVICE_DEFECT', 'maintenance02defect');
insert into log(id,time,action_name,action_info) values ( 10, '2011-03-05', 'DEVICE_REPAIRED', 'maintenance03repaired');

select 
  maintenance.start as start
, maintenance.stop as stop
, count (device_action.*) as device_actions
from (select 
  l_start.time as start
  , (select time 
      from log l_stop 
      where l_stop.time > l_start.time 
      and l_stop.action_name = 'MAINTENANCE_STOP'
      order by time asc limit 1) as stop
  from log l_start
  where l_start.action_name='MAINTENANCE_START' order by l_start.time asc) maintenance
left join log device_action
  on device_action.time > maintenance.start
  and device_action.time < maintenance.stop
  and device_action.action_name like 'DEVICE_%'
group by maintenance.start
  , maintenance.stop
order by maintenance.start asc
;

Будьте осторожны с производительностью. Если Postgres не оптимизировал вложенный запрос, это заняло бы O (n ^ 2) времени.

Если вы можете:

  1. Изменить структуру. Например. одна таблица DEVICE_MAINTENANCES с идентификатором обслуживания и вторая таблица DEVICE_MAINTENANCE_ACTIONS с внешним ключом DEVICE_MAINTENANCES.ID. Запросы будут проще и быстрее.
  2. Если нет, обработайте time как первичный ключ (индекс воздействия)
  3. Если нет, создайте индекс для столбца time.
...