【问题标题】:Group rows by dense_rank() and loop through each sub-group and compare another column in next row of that sub group?通过dense_rank()对行进行分组并遍历每个子组并比较该子组下一行中的另一列?
【发布时间】:2020-04-06 22:15:05
【问题描述】:

我在 LINQPad 中尝试过以下操作:

create table users
(
    id int not null,
    startdate datetime not null,
    enddate datetime not null
)

go

insert into users(id, startdate, enddate) values(1, '01/01/2000', '01/02/2000')
insert into users(id, startdate, enddate) values(1, '01/03/2000', '01/04/2000')

insert into users(id, startdate, enddate) values(2, '01/01/2000', '01/02/2000')
insert into users(id, startdate, enddate) values(2, '01/03/2000', '01/04/2000')
insert into users(id, startdate, enddate) values(2, '01/05/2000', '01/06/2000')

insert into users(id, startdate, enddate) values(3, '01/01/2000', '01/02/2000')
insert into users(id, startdate, enddate) values(3, '01/03/2000', '01/04/2000')
insert into users(id, startdate, enddate) values(3, '01/06/2000', '01/07/2000')

insert into users(id, startdate, enddate) values(4, '01/01/2000', '01/02/2000')

go

select * from users 

go

// This query gave the result seen in the image

select id, startdate, enddate, rownum = dense_rank() over(partition by id order by enddate) from users

我想编写一个只返回 ID 1 和 2(而不是 3 和 4)的查询,因为:

  • ID 1 - 多于 1 行,其 rownum 2 的开始日期为 1 天 在其 rownum 1 的 enddate 之前
  • ID 2 - 有超过 1 行并且 它的 rownum n + 1 的 startdate 比它的 rownum 的 enddate 早 1 天 n
  • ID 3 - 虽然有超过 1 行,但其 rownum 3 的开始日期是 不是其 rownum 2 的结束日期提前 1 天(但 2 天)。因此,它是 不合格
  • ID 4 - 不超过 1 行。因此,它不是 合格

请告诉我如何得到这个结果?

【问题讨论】:

  • 那么您期望的结果是什么:只是满足条件的ids 列表(这将是两条记录,其值为12),或者所有ids 满足条件的记录?
  • 只是 ID 列表,即两条记录 - 1 和 2

标签: sql sql-server group-by subquery window-functions


【解决方案1】:

您可以使用窗口函数lag() 恢复之前的enddate,然后在having 子句中进行聚合和过滤:

select id
from (
    select 
        t.*,
        lag(enddate) over(partition by id order by enddate) lag_enddate
    from users t
) t
group by id 
having 
    count(*) > 1
    and max(case 
        when lag_enddate is null or startdate = dateadd(day, 1, lag_enddate) 
        then 0 else 1 
    end) = 0

Demo on DB Fiddle

|编号 | | -: | | 1 | | 2 |

在不支持窗口函数的旧版 SQL Server 中,您可以使用相关子查询来模拟 lag()

select id
from (
    select 
        t.*,
        (select max(enddate) from users t1 where t1.id = t.id and t1.enddate < t.enddate) lag_enddate
    from users t
) t
group by id 
having 
    count(*) > 1
    and max(case when lag_enddate is null or startdate = dateadd(day, 1, lag_enddate) then 0 else 1 end) = 0

Demo on DB Fiddle

【讨论】:

  • 谢谢。你能把
  • @MAK:我用没有LAG()的解决方案更新了我的答案
猜你喜欢
  • 2010-11-19
  • 1970-01-01
  • 2021-04-29
  • 2020-08-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-03
  • 1970-01-01
相关资源
最近更新 更多