概述:我有SHIFT_LOG
,SHIFT_LOG_DET
和SHIFT_LOG_ENTRY
表,它们具有Parent-Child-GrandChild关系(一对多)。所以,
问题:对于给定的班次,我可以使用以下查询来获取所有运算符及其条目。我不能做的是找到操作员在特定条目类型上花费的时间。即两行ENTRY_TIME之差。
SELECT
ent.ID as ENT_ID,
det.ID as DET_ID,
usr.CODE as USR_ID,
ent.SHIFT_LOG_DET_ID,
ent.ENTRY_TYPE,
IIF(ent.ENTRY_TYPE = 0 , 'ADDED',
IIF(ent.ENTRY_TYPE = 1 , 'STARTED',
IIF(ent.ENTRY_TYPE = 2 , 'ON-BREAK',
IIF(ent.ENTRY_TYPE = 3 , 'JOINED',
IIF(ent.ENTRY_TYPE = 4 , 'ENDED', 'UNKNOWN ENTRY'))))) as ENTRY_TYPE_VALUE,
ent.ENTRY_TIME+cast('31.12.1899' as timestamp) as ENTRY_TIME
FROM SHIFT_LOG_ENTRY ent
LEFT JOIN SHIFT_LOG_DET det on det.ID = ent.SHIFT_LOG_DET_ID
LEFT JOIN SHIFT_LOG log on log.ID = det.SHIFT_LOG_ID
LEFT JOIN USERS usr on usr.USERID = det.OPERATOR_ID
WHERE log.ID = 1
GROUP BY
usr.CODE,
ent.SHIFT_LOG_DET_ID,
det.ID,
ent.ID,
ENTRY_TYPE_VALUE,
ent.ENTRY_TIME,
ent.ENTRY_TYPE
结果集:
所以Inteval是在特定ENTRY_TYPE上花费的时间(以秒为单位)。即
ROW(1).Interval = ( Row(2).EntryTime - Row(1).EntryTime )
条目类型ENDED
没有间隔,因为班次结束后没有其他用户条目。
Firebird版本为2.5.3
答案 0 :(得分:2)
这是一种不同的“主动”方法。是否适合您的工作流程由您自己决定。它是基于添加特殊的额外列而将相邻行链接在一起的。
由于LOG_ENTRY
是事件的日志,并且是来自同一来源的事件,并且事件相当长(对于计算机来说15秒是很多时间),因此我认为
如果这些假设成立,我将在表中再增加一列(索引!):batch_internal_id
。它将在您选择的第1行开始为零,在下一行为1,在第3行为2,依此类推。当批次更改时,它将重置为零(在屏幕快照的第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 trigger自动填充新的内部(相对于批次)ID字段,前提是您已做出保证,并且所插入的事件始终是批次中的最后一个。
类似这样的东西:
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
这样的触发器将在启动新批次时将相对ID初始化为零,如果该批次已经有其他行,则使用最后一个ID递增。
但是,当所有相同批次的前几行都已插入而下一行还没有插入时,则始终依赖于按顺序调用它。
也可以将命令编写得更简洁一些,但可能更难阅读。
.......
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
答案 1 :(得分:1)
您需要从相关条目中选择下一个日期。您可以使用类似的方法来做到这一点:
select
SHIFT_LOG_DET_ID,
ENTRY_TIME,
datediff(minute from ENTRY_TIME to NEXT_ENTRY_TIME) as DURATION
from (
select
a.SHIFT_LOG_DET_ID,
a.ENTRY_TIME,
(select min(ENTRY_TIME)
from SHIFT_LOG_ENTRY
where SHIFT_LOG_DET_ID = a.SHIFT_LOG_DET_ID
and ENTRY_TIME > a.ENTRY_TIME) as NEXT_ENTRY_TIME
from SHIFT_LOG_ENTRY a
) b
另请参阅此fiddle。
在Firebird 3中,您可以使用window function LEAD
来实现:
select
SHIFT_LOG_DET_ID,
ENTRY_TIME,
datediff(minute from ENTRY_TIME
to lead(ENTRY_TIME) over (partition by SHIFT_LOG_DET_ID order by ENTRY_TIME)) as DURATION
from SHIFT_LOG_ENTRY
此解决方案由AlphaTry
提供select
ENT_ID,
DET_ID,
USR_CODE,
SHIFT_LOG_DET_ID,
ENTRY_TYPE,
ENTRY_TYPE_VALUE,
ENTRY_TIME,
datediff(second from ENTRY_TIME to NEXT_ENTRY_TIME) as DURATION
from (
SELECT
ent.ID as ENT_ID,
det.ID as DET_ID,
usr.CODE as USR_CODE,
ent.SHIFT_LOG_DET_ID,
ent.ENTRY_TYPE as ENTRY_TYPE,
case (ent.ENTRY_TYPE)
when '0' then 'ADDED'
when '1' then 'STARTED'
when '2' then 'ON-BREAK'
when '3' then 'JOINED'
when '4' then 'ENDED'
else 'UNKNOWN ENTRY'
end as ENTRY_TYPE_VALUE,
ent.ENTRY_TIME+cast('31.12.1899' as timestamp) as ENTRY_TIME,
(
select min(ENTRY_TIME)
from SHIFT_LOG_ENTRY
where SHIFT_LOG_DET_ID = ent.SHIFT_LOG_DET_ID
and ENTRY_TIME > ent.ENTRY_TIME
)+cast('31.12.1899' as timestamp) as NEXT_ENTRY_TIME
FROM SHIFT_LOG_ENTRY ent
LEFT JOIN SHIFT_LOG_DET det on det.ID = ent.SHIFT_LOG_DET_ID
LEFT JOIN SHIFT_LOG log on log.ID = det.SHIFT_LOG_ID
LEFT JOIN USERS usr on usr.USERID = det.OPERATOR_ID
WHERE log.ID = 1
GROUP BY
usr.CODE,
ent.SHIFT_LOG_DET_ID,
det.ID,
ent.ID,
ENTRY_TYPE_VALUE,
ent.ENTRY_TIME,
ent.ENTRY_TYPE
) b