【问题标题】:Using RANK OVER PARTITION to Compare a Previous Row Result使用 RANK OVER PARTITION 比较前一行结果
【发布时间】:2021-11-09 03:33:57
【问题描述】:

我正在处理一个包含(以及其他列)用户 ID 和 startDate 的数据集。目标是创建一个新列“isRehire”,将他们的 startDate 与之前的 startDates 进行比较。

如果 startDates 之间的差在 1 年内,isRehire = Y。

当用户的 startDates 超过 2 个时,困难和我的问题就出现了。如果第 3 次和第 1 次 startDate 之间的差异超过一年,则第 3 次 startDate 将是重新雇用的新“基准日期”。

userID startDate isRehire
123 07/24/19 N
123 02/04/20 Y
123 08/25/20 N
123 12/20/20 Y
123 06/15/21 Y
123 08/20/21 Y
123 08/30/21 N

在上面的示例中,您可以直观地看到问题。第一个 startDate 07/24/19,用户不是 Rehire。第二个 startDate 02/04/20,他们是 Rehire。 3rd startDate 2020 年 8 月 25 日用户不是重新雇用,因为距他们最初的 startDate 已经超过 1 年。这是新的“锚”日期。

接下来的 3 个实例都是 Y,因为它们在新的“锚定”日期 08/25/20 的 1 年内。 21 年 8 月 30 日的最终开始日期是 2020 年 8 月 25 日过去一年多,表示“N”,“周期”再次重置,21 年 8 月 30 日作为新的“锚”日期。

我的目标是利用 RANK OVER PARTITION 来完成此任务,因为从我的测试来看,我相信必须有一种方法可以将等级分配给日期,然后可以将其包装在 select 语句中,以便 CASE 表达式成为书面。虽然我完全有可能完全找错了树。

您可以在下面看到一些我尝试用来完成此操作的代码,尽管到目前为止还没有取得多大成功。

select TestRank,
startDate,
userID,
CASE WHEN TestRank = TestRank THEN (TestRank - 1
                                            ) ELSE '' END AS TestRank2
from
(

select userID,
startDate
RANK() OVER (PARTITION BY userID
            ORDER BY startDate desc)
            as TestRank
from [MyTable] a
WHERE a.userID = [int]

) b 

【问题讨论】:

  • 为什么最后一行是“N”?这不符合你的逻辑。
  • 谢谢@Dale K
  • @Godon Linoff - 是的。请参阅表格下方的 2 段,了解为什么最后一个条目是“N”

标签: sql sql-server dense-rank sql-rank


【解决方案1】:

这是一个复杂的逻辑,窗口函数是不够的。为了解决这个问题,你需要迭代——或者用 SQL 来说,递归 CTE:

with t as (
      select t.*, row_number() over (partition by id order by startdate) as seqnum
      from mytable t
     ),
     cte as (
      select t.id, t.startdate, t.seqnum, 'N' as isrehire, t.startdate as anchordate
      from t
      where seqnum = 1
      union all
      select t.id, t.startdate, t.seqnum,
             (case when t.startdate > dateadd(year, 1, cte.anchordate) then 'N' else 'Y' end),
             (case when t.startdate > dateadd(year, 1, cte.anchordate) then t.startdate else cte.anchordate end)
      from cte join
           t
           on t.seqnum = cte.seqnum + 1
     )
select *
from cte
order by id, startdate;

Here 是一个 dbfiddle。

【讨论】:

  • 谢谢你。我是学习 SQL 的新手,您的回答向我介绍了递归 CTE 并解决了我的问题。
  • @Rahmor 。 . .作为 SQL 初学者,这是一个相当复杂的问题。
猜你喜欢
  • 2016-05-14
  • 2012-12-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-04
  • 2020-10-22
  • 1970-01-01
相关资源
最近更新 更多