SQL:仅选择以给定间隔与其他结果分隔的值的行
Posted
技术标签:
【中文标题】SQL:仅选择以给定间隔与其他结果分隔的值的行【英文标题】:SQL: Select rows only with values separated by a given interval from other results 【发布时间】:2017-02-10 23:44:16 【问题描述】:假设我有一个看起来像这样的表格,以秒为单位提供各种事件的时间。
event_time
----------
11
14
18
20
25
39
42
43
50
我正在尝试提出一个查询,该查询将为我提供该表中的一组行,其中每一行与 result 中的其他行至少相隔 10 秒。 p>
期望的结果是:
event_time
----------
11
25
39
50
包含event_time=11
的行是因为它前面没有任何内容。带有event_time=25
的行是下一个要返回的行,因为它是距离带有event_time=11
的行至少10 秒的第一行。
我正在使用 Postgres。我可以使用递归查询/CTE 来做到这一点,但如果不使用 ORDER BY、LIMIT 等子句就无法做到这一点,而且 Postgres 显然不允许在递归查询中使用这些。
【问题讨论】:
托管 SQL 的编程语言是什么?为什么要尝试用 SQL 来做呢? 因为我希望尽可能在数据库中对其进行评估,而不是依赖于通过网络传输整个数据集以在客户端上进行处理。 您需要为此使用递归 CTE。如果您有大量数据,在应用程序端执行此操作可能更有效。 【参考方案1】:我可以使用递归查询/CTE 来做到这一点,但如果不使用 ORDER BY、LIMIT 等子句就无法做到这一点,而且 Postgres 显然不允许在递归查询中使用这些。
with recursive
t(x) as ( --Test data
select * from unnest('11,14,18,20,25,39,42,43,50,55,60,61,69,70,71'::int[])
order by random()),
r(x) as (
select min(x) as x from t
union all
(select t.x from t join r on (t.x >= r.x + 10) order by t.x limit 1))
select * from r;
http://rextester.com/VHOGH66762
但我个人更喜欢the solution with stored function。
【讨论】:
太棒了!这几乎正是我尝试过的,但没有括号围绕union all
之后的语句,它会以ERROR: LIMIT in a recursive query is not implemented
失败。
@avalys 实际上,union
子句很常见。只是比较:rextester.com/FUO17127
查询真的很好,值得接受。我只会添加某种警告,您不应该将它用于大型数据集。我的简单 plpgsql 解决方案会快很多倍。
@klin 如您所见,我在答案中提到我更喜欢您的解决方案。实际上,我的回答是针对所提供的报价,而不是针对整个问题。
@avalys 但是看看klin's solution - 它会更有效率。 rextester.com/BQBH89836 - 递归查询需要 2.62 秒,函数需要 0.6 秒。【参考方案2】:
您可以使用 plpgsql,这对于大型数据集来说似乎很简单且非常有效(与假设的递归查询相比)。
create or replace function strain_events()
returns setof events language plpgsql as $$
declare
curr record;
prev int;
begin
for curr in
select *
from events
order by 1
loop
if prev is null or curr.event_time >= prev + 10 then
return next curr;
prev = curr.event_time;
end if;
end loop;
end $$;
select * from strain_events();
【讨论】:
这也是我的想法。但是如果有一个事件正好相差 10,这就会中断。 因为我的第一次尝试不成功,我发布了一个替代解决方案。【参考方案3】:我认为这个查询会起作用
select distinct event_time_b
from
(
select event_time_a , min(event_time_b) event_time_b
from
(
select a.event_time event_time_a , b.event_time event_time_b , b.event_time-a.event_time diff
from (select 0 as event_time union select event_time from so_ques) a , so_ques b
where a.event_time<>b.event_time
and b.event_time-a.event_time>=10
order by a.event_time
) a
group by event_time_a
order by event_time_a
) a
order by 1
;
表名 = so_ques(为测试而创建)
【讨论】:
也不起作用。试过了。检查这个案例:insert into so_ques values (11),(14),(18),(20),(25),(39),(42),(43),(50),(55), (60), (61), (69), (70), (71);
以上是关于SQL:仅选择以给定间隔与其他结果分隔的值的行的主要内容,如果未能解决你的问题,请参考以下文章