| RecordId | high_speed | speed | DateFrom | DateTo |
---------------------------------------------------------------
| 666542 | 60 | 10 | 09/11/2011 | 10/11/2011 |
| 666986 | 20 | 20 | 11/11/2011 | 11/11/2011 |
| 666996 | 0 | 0 | 13/11/2011 | 17/11/2011 |
| 755485 | 0 | 0 | 01/11/2011 | 14/11/2011 |
| 758545 | 70 | 50 | 15/11/2011 | 26/11/2011 |
| 796956 | 40 | 40 | 09/11/2011 | 09/11/2011 |
| 799656 | 25 | 20 | 09/11/2011 | 09/11/2011 |
| 808845 | 0 | 0 | 15/11/2011 | 15/11/2011 |
| 823323 | 0 | 0 | 15/11/2011 | 16/11/2011 |
| 823669 | 0 | 0 | 17/11/2011 | 18/11/2011 |
| 899555 | 0 | 0 | 18/11/2011 | 19/11/2011 |
| 990990 | 20 | 10 | 12/11/2011 | 12/11/2011 |
这里,我想构建数据库视图,它组合了速度= 0的连续行。在这种情况下,DateFrom将是第一行和第一行的DateFrom值。 DateTo将是最后一行的DateTo值。 表格结果如下:
| high_speed | speed | DateFrom | DateTo |
---------------------------------------------------
| 60 | 10 | 09/11/2011 | 10/11/2011 |
| 20 | 20 | 11/11/2011 | 11/11/2011 |
| 0 | 0 | 13/11/2011 | 14/11/2011 |
| 70 | 50 | 15/11/2011 | 26/11/2011 |
| 40 | 40 | 09/11/2011 | 09/11/2011 |
| 25 | 20 | 09/11/2011 | 09/11/2011 |
| 0 | 0 | 15/11/2011 | 19/11/2011 |
| 20 | 10 | 12/11/2011 | 12/11/2011 |
有没有办法在数据库视图或函数中获得结果?
注意 - 1.删除了devID列。这是非常令人困惑的,而不是它增加了另一列来理解这个问题。 另外,我需要添加一个“ Period ”列,即与“DateFrom”& “DateTo”栏目。
答案 0 :(得分:2)
此查询使用分析函数lag()
,lead()
和一些带case ... when
的逻辑提供所需的输出:
select high_speed, speed, datefrom, dateto, dateto-datefrom period
from (
select recordid, 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
答案 1 :(得分:1)
这是同一解决方案的另一种方法。它使用lag()
,lead()
和partition by
与前一解决方案的不同之处在于此查询将行绑定连续的时间间隔,即:
考虑速度为0的所有行。
结果:
另请注意,与15 / 11-15 / 11和13 / 11-17 / 11共享相同日期的句点将会破坏此查询。提供的示例数据具有此类句点。< / p>
-- for better understanding, start reading from the most nested query to the outer
-- QUERY 4: Removes duplicates
-- this query removes duplicates, because both border-rows on a multiple-row period will be identical
-- after the query 3
select distinct
high_speed,
speed,
datefrom,
dateto,
dateto-datefrom period
from
(
-- QUERY 3: Selects border-rows and builds datefrom and dateto.
-- this query selects all border-rows, which have the datefrom and dateto data that we need
-- to build the bigger period row.
--
-- this query also builds the bigger period datefrom and dateto
select
high_speed,
speed,
CASE WHEN is_previous_a_border = 0 and is_next_a_border = 1 then lag(datefrom) over (partition by speed order by datefrom)
WHEN is_previous_a_border = 1 and is_next_a_border = 0 then datefrom
WHEN is_previous_a_border = 1 and is_next_a_border = 1 then datefrom
ELSE null END datefrom,
CASE WHEN is_previous_a_border = 0 and is_next_a_border = 1 then dateto
WHEN is_previous_a_border = 1 and is_next_a_border = 0 then lead(dateto) over (partition by speed order by datefrom)
WHEN is_previous_a_border = 1 and is_next_a_border = 1 then dateto
ELSE null END dateto
from (
-- QUERY 2: Create syntax-sugar
-- this query creates some syntax-sugar properties:
-- - "is_previous_a_border": defines if previous row is a border
-- - "is_next_a_border": defines if previous row is a border
select
high_speed,
speed,
datefrom,
dateto,
is_border,
nvl(lag(is_border) over (partition by speed order by datefrom), 1) as is_previous_a_border,
nvl(lead(is_border) over (partition by speed order by datefrom), 1) as is_next_a_border
from (
-- QUERY 1: Create "is_border" property
-- this query creates the "is_border" property, which defines if a row is a border of a bigger multiple-row period
-- we use partition by to group rows and lag/lead to flag rows with consecutive periods
--
-- note that both border-rows of a bigger multiple-row period will have is_border = 1, while all rows in between
-- them, will have is_border = 0.
select
high_speed,
speed,
datefrom,
dateto,
case when lead(datefrom) over (partition by speed order by datefrom) between datefrom and dateto + interval '1' day
and lag(dateto) over (partition by speed order by datefrom) between datefrom - interval '1' day and dateto then 0
else 1 end is_border
from
test))
where is_border = 1)
order by
speed, datefrom;