Dette er et hul-og-ø-problem, men øerne er defineret af en REQ
transaktion gør det lidt mere kompliceret end nogle andre.
Du kan bruge indlejrede lead- og lag-funktioner og noget manipulation for at få det, du har brug for:
select distinct item,
coalesce(start_tran,
lag(start_tran) over (partition by item order by timestamp)) as start_tran,
coalesce(end_tran,
lead(end_tran) over (partition by item order by timestamp)) as end_tran,
coalesce(end_time,
lead(end_time) over (partition by item order by timestamp))
- coalesce(start_time,
lag(start_time) over (partition by item order by timestamp)) as time
from (
select item, timestamp, start_tran, start_time, end_tran, end_time
from (
select item,
timestamp,
case when lag_tran is null or transaction like 'REQ%'
then transaction end as start_tran,
case when lag_tran is null or transaction like 'REQ%'
then timestamp end as start_time,
case when lead_tran is null or lead_tran like 'REQ%'
then transaction end as end_tran,
case when lead_tran is null or lead_tran like 'REQ%'
then timestamp end as end_time
from (
select item, transaction, timestamp,
lag(transaction)
over (partition by item order by timestamp) as lag_tran,
lead(transaction)
over (partition by item order by timestamp) as lead_tran
from transactions
)
)
where start_tran is not null or end_tran is not null
)
order by item, start_tran;
Med yderligere registreringer for en anden cyklus for punkt 1 og 2, der kunne give:
ITEM START_TRAN END_TRAN TIME
---------- ---------- ---------- -----------
1 REQ-A PICKUP 0 1:53:30.0
1 REQ-E PICKUP 0 1:23:30.0
2 REQ-B MAIL 0 0:24:13.0
2 REQ-F REQ-F 0 0:0:0.0
3 REQ-C PICKUP 0 1:46:30.0
4 REQ-D PULL 0 0:23:59.0
5 REQ-A PICKUP 0 1:43:59.0
SQL violin viser alle de mellemliggende trin.
Det er ikke helt så skræmmende, som det kan se ud ved første øjekast. Den inderste forespørgsel tager de rå data og tilføjer en ekstra kolonne for lead- og lagtransaktioner. Tager kun det første sæt af post-1 poster, der ville være:
ITEM TRANSACTION TIMESTAMP LAG_TRAN LEAD_TRAN
---------- ----------- ------------------------ ---------- ----------
1 REQ-A 2014-07-31T09:51:32Z PULL
1 PULL 2014-07-31T10:22:21Z REQ-A TRANSFER
1 TRANSFER 2014-07-31T10:22:23Z PULL ARRIVE
1 ARRIVE 2014-07-31T11:45:01Z TRANSFER PICKUP
1 PICKUP 2014-07-31T11:45:02Z ARRIVE REQ-E
Bemærk REQ-E
dukker op som den sidste lead_tran
? Det er den første transaction
for den anden cyklus af poster for denne vare, og vil være nyttig senere. Det næste niveau af forespørgsel bruger disse lead- og lag-værdier og behandler REQ
værdier som start- og slutmarkører og bruger denne information til at nulstille alt undtagen den første og sidste post for hver cyklus.
ITEM TIMESTAMP START_TRAN START_TIME END_TRAN END_TIME
---------- ------------------------ ---------- ------------------------ ---------- ------------------------
1 2014-07-31T09:51:32Z REQ-A 2014-07-31T09:51:32Z
1 2014-07-31T10:22:21Z
1 2014-07-31T10:22:23Z
1 2014-07-31T11:45:01Z
1 2014-07-31T11:45:02Z PICKUP 2014-07-31T11:45:02Z
Det næste niveau af forespørgsel fjerner alle rækker, der ikke repræsenterer starten eller slutningen (eller begge dele - se REQ-F
i Violinen), da vi ikke er interesserede i dem:
ITEM TIMESTAMP START_TRAN START_TIME END_TRAN END_TIME
---------- ------------------------ ---------- ------------------------ ---------- ------------------------
1 2014-07-31T09:51:32Z REQ-A 2014-07-31T09:51:32Z
1 2014-07-31T11:45:02Z PICKUP 2014-07-31T11:45:02Z
Vi har nu par af rækker for hver cyklus (eller en enkelt række for REQ-F
). Det sidste niveau bruger bly og lag igen til at udfylde de tomme felter; hvis start_tran
er null, så er dette en slutrække, og vi bør bruge den forrige rækkes startdata; hvis end_tran
er null, så er dette en startrække, og vi skal bruge den næste rækkes slutdata.
ITEM START_TRAN START_TIME END_TRAN END_TIME TIME
1 REQ-A 2014-07-31T09:51:32Z PICKUP 2014-07-31T11:45:02Z 0 1:53:30.0
1 REQ-A 2014-07-31T09:51:32Z PICKUP 2014-07-31T11:45:02Z 0 1:53:30.0
Det gør begge rækker ens, så den distinct
fjerner dubletterne.