Sql 分组行时考虑;差异“;行间
我有一个包含开始时间(在示例中使用数字保持简单)和事件持续时间的表 我想确定“块”及其开始和结束时间。Sql 分组行时考虑;差异“;行间,sql,oracle,oracle11g,Sql,Oracle,Oracle11g,我有一个包含开始时间(在示例中使用数字保持简单)和事件持续时间的表 我想确定“块”及其开始和结束时间。 当前一行(按开始时间排序)的结束时间(开始时间+持续时间)与当前行的开始时间之间的差值>=5时,应开始一个新的“块” 这是我的测试数据,包括注释中的图形解释: WITH test_data AS ( SELECT 0 s, 2 dur FROM dual UNION ALL --# ■■ SELECT 2 , 2 FROM dual UNION ALL --#
当前一行(按开始时间排序)的结束时间(开始时间+持续时间)与当前行的开始时间之间的差值
>=5
时,应开始一个新的“块”
这是我的测试数据,包括注释中的图形解释:
WITH test_data AS (
SELECT 0 s, 2 dur FROM dual UNION ALL --# ■■
SELECT 2 , 2 FROM dual UNION ALL --# ■■
SELECT 10 , 1 FROM dual UNION ALL --# ■
SELECT 13 , 4 FROM dual UNION ALL --# ■■■■
SELECT 15 , 4 FROM dual --# ■■■■
)
--# Should return
--# 0 .. 4 --# ■■■■
--# 10 .. 19 --# ■■■■■■■■■
第一个块从0
开始,到4
结束。由于与下一行的差值为=5
,因此在10
处开始另一个块,该块在19
处结束
我可以使用
LAG
识别块的第一行,但我还没有找到如何继续
我可以在PL/SQL循环中解决这个问题,但出于性能原因,我试图避免这样做
关于如何编写此查询有什么建议吗
提前感谢,Peter在MS-SQL中,我将使用
行数()OVER(按开始时间排序)作为秩
来在开始时间对行进行排序
然后,我将编写一个查询,将每一行连接到具有前一个秩的行,并设置一个标志,如果差值大于5或NULL(第一行)
然后,我将选择具有此标志的所有行,这些行是起始行,对于此子集,重复对行进行编号并连接到下一行的过程,以获得时间跨度:
blockstarttime1 nextstarttime1 (=starttime2)
blockstarttime2 nextstarttime2 (=starttime3)
blockstarttime3 NULL
最后,可以使用将此数据集连接到原始数据,其中starttime位于blockstarttime和nextstarttime之间,以对结果进行分区
由您将此翻译成Oracle…Richard Snodgrass的一本精彩的书可能会有帮助:(免费下载),我发现这本书在处理数据库中的时间时非常宝贵
查看一些书籍更正和相关的zip格式CD-ROM的链接。代码有点复杂,有许多子查询等。这些数据可能不起作用,但我想不出有什么现成的
处理时态数据总是一件痛苦的事情
WITH test_data AS (
SELECT 0 s, 2 dur FROM dual UNION ALL --# ■■
SELECT 2 , 2 FROM dual UNION ALL --# ■■
SELECT 10 , 1 FROM dual UNION ALL --# ■
SELECT 13 , 4 FROM dual UNION ALL --# ■■■■
SELECT 15 , 4 FROM dual --# ■■■■
)
select
-- Group on each block
min(start_time) as s,
max(end_time) - min(start_time) as dur
from (
select
start_time,
duration,
end_time,
-- number the blocks sequentially
sum(is_block_start) over (order by start_time) as block_num
from (
select
start_time,
duration,
end_time,
-- Mark the start of each block
case
when nvl2(prev_end_time, start_time - prev_end_time,5) >= 5
then 1 else 0 end as is_block_start
from (
select
s as start_time,
dur as duration,
s+dur as end_time,
lag(s+dur) over (order by s) prev_end_time
from test_data
)
)
)
group by block_num
我使用子查询和分析来识别和分组连续范围:
SQL> WITH test_data AS (
2 SELECT 0 s, 2 dur FROM dual UNION ALL --# ■■
3 SELECT 2 , 2 FROM dual UNION ALL --# ■■
4 SELECT 10 , 1 FROM dual UNION ALL --# ■
5 SELECT 13 , 4 FROM dual UNION ALL --# ■■■■
6 SELECT 15 , 4 FROM dual --# ■■■■
7 )
8 SELECT MIN(s) "begin", MAX(s + dur) "end"
9 FROM (SELECT s, dur, SUM(gap) over(ORDER BY s) my_group
10 FROM (SELECT s, dur,
11 CASE
12 WHEN lag(s + dur) over(ORDER BY s) >= s - 5 THEN
13 0
14 ELSE
15 1
16 END gap
17 FROM test_data
18 ORDER BY s))
19 GROUP BY my_group;
begin end
---------- ----------
0 4
10 19
谢谢文森特!这正是我所需要的,我错过了SUM(gap)而不是…
部分。次要说明:我认为可以从内部子选择中删除s的订单
,并在必要时移动到主查询。谢谢!我在
-部分上缺少了总和(is\u block\u start)。接受文森特的回答,这或多或少与您提供的问题相同,但我发现它更容易阅读。谢谢!这应该是可行的,但它会涉及到对原始数据的另一个查询,Vincent Malgrat和MikeyByCrikey提供的解决方案避免了这一点。感谢链接,我稍后将阅读这528页:)您是否检查它是否已经在目录中?@Peter:刚刚看了一下,这本书列在“SQL(实现不可知)”下。