问题
| RecordId | foo_id | high_speed | speed | DateFrom | DateTo |
------------------------------------------------------------------------
| 666542 | 12 | 60 | 10 | 09/11/2011 | 10/11/2011 |
| 666986 | 13 | 20 | 20 | 11/11/2011 | 11/11/2011 |
| 666996 | 12 | 0 | 0 | 13/11/2011 | 17/11/2011 |
| 755485 | 12 | 0 | 0 | 01/11/2011 | 14/11/2011 |
| 758545 | 12 | 70 | 50 | 15/11/2011 | 26/11/2011 |
| 796956 | 12 | 40 | 40 | 09/11/2011 | 09/11/2011 |
| 799656 | 13 | 25 | 20 | 09/11/2011 | 09/11/2011 |
| 808845 | 12 | 0 | 0 | 15/11/2011 | 15/11/2011 |
| 823323 | 12 | 0 | 0 | 15/11/2011 | 16/11/2011 |
| 823669 | 12 | 0 | 0 | 17/11/2011 | 18/11/2011 |
| 899555 | 12 | 0 | 0 | 18/11/2011 | 19/11/2011 |
| 990990 | 12 | 20 | 10 | 12/11/2011 | 12/11/2011 |
Here, I want to construct database view which combines the consecutive rows having speed = 0. In that case, DateFrom will be the DateFrom value from first row & DateTo will be the DateTo value of last row. Which results into table as follows:
| foo_id | high_speed | speed | DateFrom | DateTo |
---------------------------------------------------
| 12 | 60 | 10 | 09/11/2011 | 10/11/2011 |
| 13 | 20 | 20 | 11/11/2011 | 11/11/2011 |
| 12 | 0 | 0 | 13/11/2011 | 14/11/2011 |
| 12 | 70 | 50 | 15/11/2011 | 26/11/2011 |
| 12 | 40 | 40 | 09/11/2011 | 09/11/2011 |
| 13 | 25 | 20 | 09/11/2011 | 09/11/2011 |
| 12 | 0 | 0 | 15/11/2011 | 19/11/2011 |
| 12 | 20 | 10 | 12/11/2011 | 12/11/2011 |
To get result with combining consecutive rows having speed = 0, I have designed view which users sql query as follows:
select foo_id, high_speed, speed, datefrom, dateto, dateto-datefrom period
from (
select recordid, foo_id, high_speed, speed, datefrom,
case when tmp = 2 then lead(dateto) over (order by recordid)
else dateto end dateto, tmp
from (
select test.*, case when speed <> 0 then 1
when lag(speed) over (order by recordid) <> 0 then 2
when lead(speed) over (order by recordid) <> 0 then 3
end tmp
from test )
where tmp is not null)
where tmp in (1, 2) order by recordid
Now, I have to apply the same result as per foo_id. To get this result, need apply filter of foo_id to inner nested query. Is it possible to create view with parameter? or how I can design any function which takes one argument which will compare with foo_id column. ex -
select foo_id, high_speed, speed, datefrom, dateto, dateto-datefrom period
from (
select recordid, foo_id, high_speed, speed, datefrom,
case when tmp = 2 then lead(dateto) over (order by recordid)
else dateto end dateto, tmp
from (
select test.*, case when speed <> 0 then 1
when lag(speed) over (order by recordid) <> 0 then 2
when lead(speed) over (order by recordid) <> 0 then 3
end tmp
from test where foo_id=12 )
where tmp is not null)
where tmp in (1, 2) order by recordid
回答1:
Four years have passed since this question was asked. But Oracle added the MATCH_RECOGNIZE clause to Oracle 12c, and this made the solution simpler.
SELECT
foo_id, high_speed, speed,
NVL(DateFromZ, DateFrom) DateFrom,
NVL(DateToZ, DateTo) DateTo
FROM test
MATCH_RECOGNIZE (
ORDER BY RecordId
MEASURES
FIRST(zeros.DateFrom) AS DateFromZ,
FINAL LAST(zeros.DateTo) AS DateToZ,
COUNT(*) AS cnt
ALL ROWS PER MATCH WITH UNMATCHED ROWS
PATTERN (zeros+)
DEFINE
zeros AS zeros.speed = 0
)
WHERE speed > 0 OR cnt = 1
ORDER BY RecordId;
Output:
+--------+------------+-------+------------+------------+
| FOO_ID | HIGH_SPEED | SPEED | DATEFROM | DATETO |
+--------+------------+-------+------------+------------+
| 12 | 60 | 10 | 09/11/2011 | 10/11/2011 |
| 13 | 20 | 20 | 11/11/2011 | 11/11/2011 |
| 12 | 0 | 0 | 13/11/2011 | 14/11/2011 |
| 12 | 70 | 50 | 15/11/2011 | 26/11/2011 |
| 12 | 40 | 40 | 09/11/2011 | 09/11/2011 |
| 13 | 25 | 20 | 09/11/2011 | 09/11/2011 |
| 12 | 0 | 0 | 15/11/2011 | 19/11/2011 |
| 12 | 20 | 10 | 12/11/2011 | 12/11/2011 |
+--------+------------+-------+------------+------------+
Demo on db<>fiddle.
来源:https://stackoverflow.com/questions/30958088/sql-oracle-combining-consecutive-rows-with-filter