2

目标是接受收到的第一个投诉并拒绝在第一个投诉后 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:01

所需输出:

投诉编号 约会时间 地位
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:01 接受

我知道使用编程语言会很容易,但是我需要一个 SQL 解决方案。

编辑:

根据@Gordon 的建议,我实现了以下递归查询并且它有效!但是,它在大数据上似乎效率低下。

with RECURSIVE t AS (
    select row_number as rn,ts, lag(ts,1) over (order by row_number) as baseline from main_table where row_number<3
  UNION ALL
    SELECT 
    rn+1 as rn 
    ,(select ts from main_table where row_number=rn+1) as ts
    ,case when datediff('hour',ts,baseline)>24 then ts else baseline end as baseline
     from (select * FROM t order by rn desc limit 1 )t where rn<=(select count(*)-1 from main_table)
)

,real_baseline as 
(
select rn,ts,lead(baseline,1) over (order by rn) as real_baseline from t
)

select * 
,case when row_number() over (partition by real_baseline order by ts) =1 then 'Accept'
else 'Reject' end as status
from real_baseline

4

3 回答 3

0

这是简单的方法。将每个 datetime 截断为 Hour 然后在每个小时内将 First 或 Minimum datetime 作为 accept ,将 other 作为 denied 。

PS 我已经使用 table_name 作为投诉更改它。在 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 ;
于 2021-04-09T05:54:03.330 回答
0

通常你可以应用领先/滞后,但不是在这里。领先/滞后的问题是所需的不可预测范围。同样,递归 CTE 似乎不可行,因为它需要递归部分中的 MIN 函数;但是,这是不允许的。由于一个函数是令人满意的,也许最好的函数是返回一个表。见小提琴

create or replace function public.accept_reject_complaints()
 returns table( o_complaintid integer
              , o_datetime    timestamp 
              , o_status      text
              )
 language plpgsql
AS $$                 
declare
    l_current_end_ts timestamp = '-infinity'::timestamp;

    c_complaint_list cursor for
                     select complaintid, datetime     
                       from complaints
                      order by datetime;
begin
    for complaint_rec in c_complaint_list 
    loop
       if complaint_rec.datetime  > l_current_end_ts then 
          o_status = 'Accept'; 
          l_current_end_ts = complaint_rec.datetime  + interval '1 hour';
       else 
          o_status = 'Reject'; 
       end if; 
   
       o_datetime = complaint_rec.datetime;
       o_complaintid = complaint_rec.complaintid;
       return next; 
    end loop ;

end ; 
$$;

不幸的是,由于它涉及游标循环,因此对于大数据量来说,性能将是一个问题。

于 2021-04-09T03:07:31.733 回答
0
  1. 使用 的连续性ComplaintID,查询为:
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

DB小提琴

  1. 提取每一行,Accept查询是:
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

DB小提琴

于 2021-04-09T12:49:09.857 回答