问题
This is a gaps and islands problem.
Meter_id |Realtimeclock |I_Y|I_B|I_X|
201010 |27-09-2018 00:00:00|1.0|2.0|3.0|
201010 |27-09-2018 00:30:00|1.0|2.0|3.0|
201010 |27-09-2018 01:00:00|1.0|2.0|3.0|
201010 |27-09-2018 01:30:00|1.0|2.0|3.0|
201010 |27-09-2018 02:00:00|1.0| 0 |3.0|
201010 |27-09-2018 02:30:00|1.0| 0 |0 |
201010 |27-09-2018 03:00:00|1.0|2.0|3.0|
201010 |27-09-2018 03:30:00|1.0|2.0|3.0|
201011 |27-09-2018 00:00:00|1.0|2.0|3.0|
201011 |27-09-2018 00:30:00|1.0|2.0|3.0|
201010 |28-09-2018 03:00:00|1.0|2.0|3.0|
201010 |28-09-2018 03:30:00|1.0|2.0|3.0|
201011 |28-09-2018 04:00:00|1.0| 0 |0 |
201011 |28-09-2018 00:00:00|1.0|2.0|3.0|
201011 |28-09-2018 00:30:00|1.0|2.0|3.0|
One approach uses the difference in row numbers method:
select * from (
WITH cte1 AS (
SELECT t.*, ROW_NUMBER() OVER (PARTITION BY Meter_id ORDER BY Realtimeclock) rn
FROM yourTable t
),
cte2 AS (
SELECT t.*, ROW_NUMBER() OVER (PARTITION BY Meter_id ORDER BY Realtimeclock) rn
FROM yourTable t
WHERE I_B <> 0
),
cte3 AS (
SELECT t1.*,
t1.rn - t2.rn AS diff
FROM cte1 t1
INNER JOIN cte2 t2
ON t1.Meter_id = t2.Meter_id AND t1.Realtimeclock = t2.Realtimeclock
)
SELECT
Meter_id,
MIN(Realtimeclock) AS start_time,
MAX(Realtimeclock) AS end_time,
COUNT(I_Y) AS I_Y,
COUNT(I_B) AS I_B,
COUNT(I_X) AS I_X,ROW_NUMBER() OVER (PARTITION BY meter_id ORDER BY meter_id ) AS Spell
FROM cte3
GROUP BY
Meter_id,
diff);
The output should print like ,,Please let me know any change required in code.
From the above table I need daywise spells as start time and endtime, based on condition I_Y,I_B,I_X which is non-zero value as countable. Here we see the start time of 201010 meter_id has two spells as there was time gap between them. Likewise it has to show all the spells along with date and timestamp.
Meter_id |start_time |End_time |I_Y|I_B|I_X|spell
201010 |27-09-2018 00:00:00|27-09-2018 01:30:00|4 |4 |4 |1
201010 |27-09-2018 03:00:00|27-09-2018 03:30:00|4 |4 |4 |2
201011 |27-09-2018 00:00:00|27-09-2018 00:30:00|2 |2 |2 |1
201010 |28-09-2018 03:00:00|27-09-2018 03:30:00|2 |2 |2 |1
201011 |28-09-2018 00:00:00|28-09-2018 00:30:00|2 |2 |2 |1
Throwing run time error as below,
[Error] Execution (35: 22): ORA-01830: date format picture ends before converting entire input string
Hi Tim,,
Please look into it.It will be a big help to me ever.
the above is cleared after giving trunc(realtimeclock) instead of TO_DATE(realtimeclock) ..
Thanks for your help Tim.
回答1:
You only need a slight modification to your current approach, to add a partition on the date (in addition to the meter_id). Then, in the final query, add a COUNT which tallies the number of spells for a given meter and date.
WITH cte1 AS (
SELECT t.*,
ROW_NUMBER() OVER (PARTITION BY Meter_id, TO_DATE(Realtimeclock)
ORDER BY Realtimeclock) rn
FROM yourTable t
),
cte2 AS (
SELECT t.*,
ROW_NUMBER() OVER (PARTITION BY Meter_id, TO_DATE(Realtimeclock)
ORDER BY Realtimeclock) rn
FROM yourTable t
WHERE I_B <> 0
),
cte3 AS (
SELECT t1.*,
t1.rn - t2.rn AS diff
FROM cte1 t1
INNER JOIN cte2 t2
ON t1.Meter_id = t2.Meter_id AND t1.Realtimeclock = t2.Realtimeclock
)
SELECT
Meter_id,
MIN(Realtimeclock) AS start_time,
MAX(Realtimeclock) AS end_time,
COUNT(I_Y) AS I_Y,
COUNT(I_B) AS I_B,
COUNT(I_X) AS I_X,
COUNT(*) OVER (PARTITION BY TO_DATE(Realtimeclock), Meter_id
ORDER BY MIN(Realtimeclock)) AS spell
FROM cte3
GROUP BY
Meter_id,
TO_DATE(Realtimeclock),
diff;
Demo
Note that this answer assumes that shifts never run from one calendar day over to the next. If this could happen, and you need to account for it, then you should give us what the logic is regarding counting such occurrences.
Demo again in SQL Server, though the above query is Oracle code and should run without any issues.
来源:https://stackoverflow.com/questions/52585046/how-to-write-a-query-for-a-gaps-and-islands-problem