2026-02-28 17:04:25 +04:00

129 lines
3.5 KiB
SQL

WITH base AS (
SELECT
t_stamp,
Name,
Full,
Half_Full,
Jam,
No_Container,
Block_Operation
FROM lane_data
WHERE t_stamp BETWEEN :startTime AND :endTime
),
-- Unpivot signals into rows
ev AS (
SELECT Name, t_stamp, 'Full' AS sig, Full AS val FROM base
UNION ALL SELECT Name, t_stamp, 'Half_Full', Half_Full FROM base
UNION ALL SELECT Name, t_stamp, 'Jam', Jam FROM base
UNION ALL SELECT Name, t_stamp, 'No_Container', No_Container FROM base
UNION ALL SELECT Name, t_stamp, 'Block_Operation', Block_Operation FROM base
),
-- Add previous and next values, and find falling edges
ch AS (
SELECT
Name,
sig,
t_stamp,
val,
LAG(val) OVER (PARTITION BY Name, sig ORDER BY t_stamp) AS prev_val,
LEAD(val) OVER (PARTITION BY Name, sig ORDER BY t_stamp) AS next_val,
LEAD(t_stamp) OVER (PARTITION BY Name, sig ORDER BY t_stamp) AS next_ts
FROM ev
),
-- Mark rising and falling edges
edges AS (
SELECT
Name,
sig,
t_stamp,
val,
CASE
WHEN val = 1 AND (prev_val = 0 OR prev_val IS NULL) THEN 1 -- rising edge
ELSE 0
END AS is_rising,
CASE
WHEN val = 0 AND prev_val = 1 THEN 1 -- falling edge
ELSE 0
END AS is_falling
FROM ch
),
-- Find interval starts (rising edges)
starts AS (
SELECT
Name,
sig,
t_stamp AS start_ts
FROM edges
WHERE is_rising = 1
),
-- Find interval ends (falling edges)
ends AS (
SELECT
Name,
sig,
t_stamp AS end_ts
FROM edges
WHERE is_falling = 1
),
-- Match each start with the next falling edge (or endTime if none exists)
intervals AS (
SELECT
s.Name,
s.sig,
s.start_ts,
COALESCE(
(SELECT MIN(e.end_ts)
FROM ends e
WHERE e.Name = s.Name
AND e.sig = s.sig
AND e.end_ts > s.start_ts),
:endTime
) AS end_ts
FROM starts s
),
-- Sum durations
dur AS (
SELECT
Name,
SUM(CASE WHEN sig = 'Full' THEN TIMESTAMPDIFF(SECOND, start_ts, end_ts) ELSE 0 END) AS Full_Duration_Sec,
SUM(CASE WHEN sig = 'Half_Full' THEN TIMESTAMPDIFF(SECOND, start_ts, end_ts) ELSE 0 END) AS Half_Full_Duration_Sec,
SUM(CASE WHEN sig = 'Jam' THEN TIMESTAMPDIFF(SECOND, start_ts, end_ts) ELSE 0 END) AS Jam_Duration_Sec,
SUM(CASE WHEN sig = 'No_Container' THEN TIMESTAMPDIFF(SECOND, start_ts, end_ts) ELSE 0 END) AS No_Container_Duration_Sec,
SUM(CASE WHEN sig = 'Block_Operation' THEN TIMESTAMPDIFF(SECOND, start_ts, end_ts) ELSE 0 END) AS Block_Operation_Duration_Sec
FROM intervals
GROUP BY Name
)
SELECT
:startTime AS `Start Time`,
:endTime AS `End Time`,
d.Name AS `Lane ID`,
CASE
WHEN d.Name LIKE 'S01%' THEN 'S01'
WHEN d.Name LIKE 'S02%' THEN 'S02'
ELSE 'N/A'
END AS `Sorter`,
COALESCE(Full_Duration_Sec, 0) AS `Full Duration Sec`,
COALESCE(Half_Full_Duration_Sec, 0) AS `Half Full Duration Sec`,
COALESCE(Jam_Duration_Sec, 0) AS `Jam Duration Sec`,
COALESCE(No_Container_Duration_Sec, 0) AS `No Container Duration Sec`,
COALESCE(Block_Operation_Duration_Sec, 0) AS `Block Operation Duration Sec`
FROM dur d
UNION ALL
SELECT
:startTime, :endTime,
'N/A', 'N/A',
0,0,0,0,0
WHERE NOT EXISTS (SELECT 1 FROM dur)
ORDER BY `Lane ID`;