Здесь другой, «активный» подход.Подходит ли он для вашего рабочего процесса, решите сами.Он основан на добавлении специального дополнительного столбца только для того, чтобы связать смежные строки.
Поскольку LOG_ENTRY
- это журнал событий, событий из одного источника и событий довольно длинных (15 секунд - много для компьютера), Я бы предположил, что
- Данные добавляются только в таблицу, они очень редко или никогда не редактируются и не удаляются
- Данные добавляются упорядоченным образом, то есть когда происходит любое событиевставляется - это событие LAST в пакете (в вашем случае пакет, кажется, означает: для данного оператора и данного сдвига).
Если эти предположения верны, я бы добавил одностолбец more (indexed!) таблицы: batch_internal_id
.Он будет начинаться с нуля в выбранной вами строке # 1, будет 1 в следующей строке, будет 2 в строке # 3 и т. Д.Он будет сброшен до нуля при изменении пакета (в строке № 8 на снимке экрана).
После этого вычисленное время будет простым непрерывным самосоединением, которое обычно должно быть быстрее, чемс большим количеством подвыборов, по одному на строку.
Примерно так:
SELECT
ent.ID as ENT_ID,
ent.SHIFT_LOG_DET_ID,
ent.ENTRY_TYPE,
DECODE(ent.ENTRY_TYPE, 0 , 'ADDED', 1 , 'STARTED', 2 , 'ON-BREAK',
3 , 'JOINED', 4 , 'ENDED', 'UNKNOWN ENTRY')
as ENTRY_TYPE_VALUE, -- better make it an extra table to join!
ent.ENTRY_TIME+cast('31.12.1899' as timestamp) as ENTRY_TIME,
ent_next.ENTRY_TIME - ent.ENTRY_TIME as time_elapsed
FROM SHIFT_LOG_ENTRY ent
LEFT JOIN SHIFT_LOG_ENTRY ent_next ON
(ent.SHIFT_LOG_DET_ID = ent_next.SHIFT_LOG_DET_ID) and
(ent.batch_internal_id + 1 = ent_next.batch_internal_id)
ORDER BY ent.SHIFT_LOG_DET_ID, ent.batch_internal_id
Хитрость заключается в том, чтобы обеспечить правильное заполнение batch_internal_id
в каждой партии и в то же времяизолированные от других партий.
Вот где вышеприведенные допущения становятся важными.Вы можете легко автоматически заполнить новое внутреннее (относительное к партии) поле идентификатора из триггера SQL , при условии, что вы дали гарантию, что вставляемое событие всегда является последним в пакете.
Примерно так:
CREATE TRIGGER SHIFT_LOG_DET_LINK_EVENTS
BEFORE UPDATE OR INSERT
ON SHIFT_LOG_DET
AS
BEGIN
NEW.batch_internal_id = 0;
SELECT FIRST(1) -- we only need one last row per same batch
prev.batch_internal_id + 1 -- next value
FROM SHIFT_LOG_DET prev
WHERE prev.SHIFT_LOG_DET_ID = NEW.SHIFT_LOG_DET_ID -- batch definition
ORDER BY prev.ENTRY_TIME DESCENDING
INTO NEW.batch_internal_id;
END
Такой триггер инициализирует относительный идентификатор с нулем при запуске нового пакета и с увеличенным последним идентификатором, если уже были другие строки для пакета.
Однако он критически зависит от того, чтобы всегда вызываться по порядку, когда все предыдущие строки той же партии уже были вставлены, и ни одна из следующих строк еще не вставлена.
Можно также написать команду немного более лаконично, но, возможно,труднее читать.
.......
AS
BEGIN
NEW.batch_internal_id =
COALESCE( (
SELECT FIRST(1) -- we only need one last row per same batch
prev.batch_internal_id + 1 -- next value
FROM SHIFT_LOG_DET prev
WHERE prev.SHIFT_LOG_DET_ID = NEW.SHIFT_LOG_DET_ID -- batch definition
ORDER BY prev.ENTRY_TIME DESCENDING
) , 0);
END