Informix - HQL - самостоятельное соединение - PullRequest
0 голосов
/ 08 мая 2018

У меня есть требование, чтобы получить разницу между отметками времени включения и выключения на основе условия. Метки времени находятся в том же столбце, но условие определяет, включено ли оно или нет. Мне нужно, чтобы мой результат отображал метки времени включения и выключения в одной строке и их разницу. Приведенный ниже запрос работает в Maria DB, но не работает в Informix, поскольку подзапрос с ограничением не разрешен в операторе выбора. Использование: IBM Informix Developer Edition V11.70. Я смогу рассчитать разницу во времени, но мне нужна помощь с преобразованием этого запроса в Informix и HQL-совместимость. Вот мой фрагмент кода:

SELECT
rec_id, 
last_change_ts as ontime, 
 (SELECT first last_change_ts 
         FROM trailer_log t_out 
    WHERE     t_out.rec_id = t_in.rec_id 
          AND t_out.last_change_ts >= t_in.last_change_ts 
          AND t_out.old_value = 'OH' 
  ORDER BY last_change_ts LIMIT 1 
          ) AS offtime
FROM
    trailer_log t_in
WHERE
    new_value='OH'
ORDER BY
    rec_id, last_change_ts

Что будет эквивалентно выполнению этого в Informix с HQL? Пример входных данных:

rec_id  last_change_ts new_value old_value
1188123 2017-10-09 12:37:46 OH  IN
1188123 2017-10-09 12:44:35 IN  OH
1188123 2017-10-09 12:57:12 OH  IN
1188123 2017-10-10 10:38:01 MT  OH
1188123 2017-10-10 10:44:30 OH  MT
1188133 2017-10-13 12:15:29 OH  HT
1188133 2017-10-13 12:24:07 HT  OH
1188143 2017-10-25 13:10:07 OH  MT
1188143 2017-10-25 13:15:56 MT  OH
1188148 2017-10-27 18:48:03 OH  HT
1188148 2017-10-31 17:27:09 SL  OH
1188150 2017-10-31 18:57:21 OH  HT
1188151 2017-11-09 07:57:51 OH  MT
1188151 2017-11-09 08:00:13 MT  OH
1188152 2017-11-10 14:56:48 OH  PL
1188152 2017-11-10 15:27:29 PL  OH

Ожидаемый результат:

 rec_id    ontime                 offtime   
    1188123 10/9/2017 12:37     10/9/2017 12:44 
    1188123 10/9/2017 12:57     10/10/2017 10:38    
    1188123 10/10/2017 10:44        
    1188133 10/13/2017 12:15    10/13/2017 12:24    
    1188143 10/25/2017 13:10    10/25/2017 13:15    
    1188148 10/27/2017 18:48    10/31/2017 17:27    
    1188150 10/31/2017 18:57        
    1188151 11/9/2017 7:57      11/9/2017 8:00  
    1188152 11/10/2017 14:56    11/10/2017 15:27

1 Ответ

0 голосов
/ 08 мая 2018

Решение для 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');
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...