SQL-如何识别给定数据中的1小时时段孤岛?
目标是接受收到的第一次投诉,并在第一次投诉后的1小时内拒绝收到的所有投诉。例如,我有下面的数据 抱怨的 日期时间 1. 2019年12月24日下午1:07 2. 2019年12月24日下午1:20 3. 2019年12月24日下午1:40 4. 2019年12月24日下午2:00 5. 2019年12月24日下午2:10 6. 2019年12月24日下午2:12 7. 2019年12月24日下午2:50 8. 2019年12月24日下午2:55 9 2019年12月24日下午3:00 10 2019年12月24日下午3:08 11 2019年12月24日下午4:00 12 2019年12月24日下午4:50 13 2019年12月24日下午7:00 14 2019年12月26日下午7:01SQL-如何识别给定数据中的1小时时段孤岛?,sql,gaps-and-islands,Sql,Gaps And Islands,目标是接受收到的第一次投诉,并在第一次投诉后的1小时内拒绝收到的所有投诉。例如,我有下面的数据 抱怨的 日期时间 1. 2019年12月24日下午1:07 2. 2019年12月24日下午1:20 3. 2019年12月24日下午1:40 4. 2019年12月24日下午2:00 5. 2019年12月24日下午2:10 6. 2019年12月24日下午2:12 7. 2019年12月24日下午2:50 8. 2019年12月24日下午2:55 9 2019年12月24日下午3:00 10 20
通常情况下,您可以应用超前/滞后,但此处不适用。超前/滞后是所需的不可预测范围的问题。同样,递归CTE似乎不可行,因为它需要在递归部分使用MIN函数;然而,这是不允许的。因为函数是令人满意的,所以最好的函数可能是返回一个表。看
不幸的是,由于它涉及游标循环,因此对于大数据量来说,性能将是一个问题。这是一个简单的方法。将每个datetime截断一小时,然后在每个小时内将第一个或最小datetime作为接受,将另一个作为拒绝 p.S我使用表名作为投诉更改。在Postgresql 8中测试。
SELECT ComplaintID,DateTime,CASE WHEN row_number() over(partition by hour order by
DateTime)=1 THEN 'Accept' else 'Reject' end as Status from
(select ComplaintID,DateTime ,date_trunc('hour',DateTime)as hour from complaint)A ;
我认为这需要一个递归CTE——这对大量数据来说是无效的。当你说“在SQL中”时,你实际上是指纯SQL,还是说它必须发生在DBMS中?它必须是单个查询,还是可以是一个过程?限制的原因是什么?过程/UDF也可以。sql-server或postgres?查看
LAG()
和LEAD()
分析sql函数,并尝试在数据中找到会话的开始,以获得结果。或者我认为你误解了目标。请查看所需输出以更好地理解。根据您的输出图像,2019年12月24日下午1:07接受,然后2019年12月24日下午3:08拒绝应为“接受”,因为在第一次投诉的2小时后,从3:08到下午3:07是下一个小时。根据我第一次的理解,一小时应该开始,在这种情况下,每一小时都是从2:07,3:07,4:07开始的?
SELECT ComplaintID,DateTime,CASE WHEN row_number() over(partition by hour order by
DateTime)=1 THEN 'Accept' else 'Reject' end as Status from
(select ComplaintID,DateTime ,date_trunc('hour',DateTime)as hour from complaint)A ;
with recursive cte as (
select 1 ComplaintID, min(DateTime) DateTime,
min(DateTime) prev
from main_table
union all
select t2.ComplaintID, t2.DateTime,
case when t1.prev + interval '1 hour' < t2.DateTime
then t2.DateTime else t1.prev end
from cte t1 join main_table t2
on t1.ComplaintID+1 = t2.ComplaintID
)
select ComplaintID, DateTime,
case when DateTime=prev
then 'Accept' else 'Reject' end Status
from cte
order by ComplaintID
with recursive cte as (
(
select ComplaintID, DateTime, 'Accept' Status
from main_table order by DateTime limit 1
)
union all
(
select t2.ComplaintID, t2.DateTime, 'Accept'
from cte t1 join main_table t2
on t1.DateTime + interval '1 hour' < t2.DateTime
order by t2.DateTime limit 1
)
)
select t1.ComplaintID, t1.DateTime, coalesce(t2.Status, 'Reject') Status
from main_table t1 left join cte t2
on t1.ComplaintID=t2.ComplaintID
order by t1.ComplaintID