Решение для Informix
Протестировано с Informix 12.10.FC6 (мне нужно обновить), но без использования каких-либо функций, отсутствующих также в 11.70, я придумал следующий MCVE ( Минимальный, Полный, Проверяемый пример ).
Следующий оператор SELECT:
SELECT t1.rec_id,
t1.last_change_ts AS ontime,
MIN(t2.last_change_ts) AS offtime
FROM trailer_log AS t1
LEFT OUTER JOIN trailer_log AS t2
ON t2.rec_id = t1.rec_id
AND t2.last_change_ts >= t1.last_change_ts
AND t2.old_value = 'OH'
WHERE t1.new_value = 'OH'
GROUP BY t1.rec_id, t1.last_change_ts
ORDER BY t1.rec_id, t1.last_change_ts;
выдает следующий вывод:
1188123 2017-10-09 12:37:46 2017-10-09 12:44:35
1188123 2017-10-09 12:57:12 2017-10-10 10:38:01
1188123 2017-10-10 10:44:30
1188133 2017-10-13 12:15:29 2017-10-13 12:24:07
1188143 2017-10-25 13:10:07 2017-10-25 13:15:56
1188148 2017-10-27 18:48:03 2017-10-31 17:27:09
1188150 2017-10-31 18:57:21
1188151 2017-11-09 07:57:51 2017-11-09 08:00:13
1188152 2017-11-10 14:56:48 2017-11-10 15:27:29
Это согласуется с запрошенным выводом, хотя оно включает значения секунд в метках времени и они отформатированы в варианте ISO 8601, который является родным для SQL.
Ключевым моментом является то, что для каждой записи с новым значением «OH» требуется следующая запись с таким же идентификатором записи и самой ранней датой (MIN), если старое значение - «OH», а отметка времени - не раньше, чем первая запись, за исключением случаев, когда нет более поздней записи, вы все еще хотите видеть время включения. «За исключением» переводится в левое внешнее соединение. Обратите внимание, что крайне важно, чтобы предложение ON включало условие фильтра для t2.old_value
; если это перемещено в предложение WHERE, вы не увидите несопоставленные строки (с нулевым временем отключения). Если вы хотите это в предложении WHERE, вам придется использовать AND (t2.old_value = 'OH' OR t2.old_value IS NULL)
.
На выборочном наборе данных, который не имеет индексов, результаты были для меня практически мгновенными (0,001221 секунды). Я не уверен, насколько хорошо это масштабируется до больших наборов данных.
Работа с HQL
Проблема в том, что HQL не удается определить тип offtime
в исходном запросе. Были предложены и опробованы различные решения с использованием приведений, но они еще не помогли.
Помогает ли это вообще?
SELECT t3.rec_id, t3.ontime, t3.offtime
FROM (SELECT t1.rec_id,
t1.last_change_ts AS ontime,
MIN(t2.last_change_ts) AS offtime
FROM trailer_log AS t1
LEFT OUTER JOIN trailer_log AS t2
ON t2.rec_id = t1.rec_id
AND t2.last_change_ts >= t1.last_change_ts
AND t2.old_value = 'OH'
WHERE t1.new_value = 'OH'
GROUP BY t1.rec_id, t1.last_change_ts
) AS t3
ORDER BY t3.rec_id, t3.ontime;
Данные
Это DDL и DML, которые я использовал для создания таблицы trailer_log
:
CREATE TABLE trailer_log
(
rec_id INTEGER NOT NULL,
last_change_ts DATETIME YEAR TO SECOND NOT NULL,
new_value CHAR(2) NOT NULL,
old_value CHAR(2) NOT NULL
);
INSERT INTO trailer_log VALUES(1188123, '2017-10-09 12:37:46', 'OH', 'IN');
INSERT INTO trailer_log VALUES(1188123, '2017-10-09 12:44:35', 'IN', 'OH');
INSERT INTO trailer_log VALUES(1188123, '2017-10-09 12:57:12', 'OH', 'IN');
INSERT INTO trailer_log VALUES(1188123, '2017-10-10 10:38:01', 'MT', 'OH');
INSERT INTO trailer_log VALUES(1188123, '2017-10-10 10:44:30', 'OH', 'MT');
INSERT INTO trailer_log VALUES(1188133, '2017-10-13 12:15:29', 'OH', 'HT');
INSERT INTO trailer_log VALUES(1188133, '2017-10-13 12:24:07', 'HT', 'OH');
INSERT INTO trailer_log VALUES(1188143, '2017-10-25 13:10:07', 'OH', 'MT');
INSERT INTO trailer_log VALUES(1188143, '2017-10-25 13:15:56', 'MT', 'OH');
INSERT INTO trailer_log VALUES(1188148, '2017-10-27 18:48:03', 'OH', 'HT');
INSERT INTO trailer_log VALUES(1188148, '2017-10-31 17:27:09', 'SL', 'OH');
INSERT INTO trailer_log VALUES(1188150, '2017-10-31 18:57:21', 'OH', 'HT');
INSERT INTO trailer_log VALUES(1188151, '2017-11-09 07:57:51', 'OH', 'MT');
INSERT INTO trailer_log VALUES(1188151, '2017-11-09 08:00:13', 'MT', 'OH');
INSERT INTO trailer_log VALUES(1188152, '2017-11-10 14:56:48', 'OH', 'PL');
INSERT INTO trailer_log VALUES(1188152, '2017-11-10 15:27:29', 'PL', 'OH');