【问题标题】:Select rows with the most recent two dates based on value changes根据值更改选择具有最近两个日期的行
【发布时间】:2021-09-11 14:06:08
【问题描述】:

我有一张桌子

Date Job_Id Employee_ID Status
2021-01-01 Teacher 10 Active
2021-02-01 Teacher 10 Active
2021-03-01 Teacher 10 Retired
2021-04-01 Teacher 10 Active
2021-01-01 Barber 11 Active
2021-02-01 Barber 11 Suspended
2021-03-01 Barber 11 Active
2021-04-01 Barber 11 Active

我想要一个查询来返回这个结果集

Date Job_Id Employee_ID Status
2021-03-01 Teacher 10 Retired
2021-04-01 Teacher 10 Active
2021-02-01 Barber 11 Suspended
2021-03-01 Barber 11 Active

本质上,它应该在状态更改时返回两条最近的记录。 我目前正在尝试使用延迟函数,但我对 SQL 还不是很精通,这就是我卡住的地方。

SELECT Date, Job_ID,Employee_ID, [Status], PrevStatus FROM 
    (
    SELECT 
Date,
    Job_ID,
      Employee_ID,
      [Status],
      LAG([Status]) OVER (PARTITION BY Job_ID ORDER BY ExtractDate ) AS PrevStatus
FROM    #Statuses
) AS a
WHERE a.PrevStatus <> [Status] AND a.PrevStatus IS NOT NULL

有人对如何修改有任何想法吗?

【问题讨论】:

  • 不是Barber Employee_ID = 11 ?
  • 这是——对不起,我模拟了数据并犯了一个错误。现已更正。

标签: sql-server tsql sql-server-2012


【解决方案1】:

嗯,我猜你需要lag() lead() 来获取下一个上一行的状态发生变化的所有行。然后,您需要在该结果上使用 row_number() 以获得最后两个。

SELECT date,
       job_id,
       employee_id,
       status
       FROM (SELECT date,
                    job_id,
                    employee_id,
                    status,
                    row_number() OVER (PARTITION BY employee_id,
                                                    job_id
                                       ORDER BY date DESC) row_number
                    FROM (SELECT date,
                                 job_id,
                                 employee_id,
                                 status,
                                 lag(status, 1, status) OVER (PARTITION BY employee_id,
                                                                           job_id
                                                              ORDER BY date ASC) prevstatus,
                                 lead(status, 1, status) OVER (PARTITION BY employee_id,
                                                                            job_id
                                                               ORDER BY date ASC) nextstatus
                                 FROM elbat) x
                    WHERE status <> prevstatus
                           OR status <> nextstatus) y
            WHERE row_number <= 2
            ORDER BY employee_id ASC,
                     date ASC;

db<>fiddle

【讨论】:

    【解决方案2】:

    看起来你想要的与每个员工的最后 2 个唯一状态相同

    SELECT *
    FROM
    (
        select *, 
               rn = row_number() over (partition by Employee_ID, [Status]
                                           order by [Date] desc)
        from   #Statuses
    ) d
    WHERE  d.rn = 1
    order by Employee_ID, [Date]
    

    【讨论】:

      【解决方案3】:

      也许,我不了解用例,但您为什么要使用 LAG?

      我会做这样的事情吗?

      SELECT MAX(Date), Job_Id, Employee_ID, Status
      FROM #Statuses
      GROUP BY Job_ID, Employee_ID, Status
      

      【讨论】:

      • 这个想法是获取最近更改的行,尽管不知道它们何时或是否被更改。我只想查看 job_ids、employee_ids 和 statuses,如果状态在给定时间段内的某个时间实际上发生了变化。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-21
      • 2019-03-29
      • 1970-01-01
      • 2021-02-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多