【问题标题】:Self Join to calcuate one day before a given date自加入计算给定日期前一天
【发布时间】:2020-09-28 21:50:21
【问题描述】:

我有这张表 Employee_Hire,其中包含部门中员工 (ID) 的雇用日期。现在我想编写一个 Select 查询,它增加了一个列(Last_day)来显示他在那个部门工作的最后一天。例如,对于部门 D01 中的 ID = 1,他的最后一天是 2014/12/31。同样在 D02 中,他的最后一天是 2017/12/31。

现在由于他仍在 D04 工作,我们可以有一个像“Till Present”这样的字符串或像 2099/12/31 这样的未来日期或任何符合目的的日期。

我想对表中的每个员工都这样做。

+---+-------------+------------+
| Id| Dept_name   | Hiredate   |
+---+-------------+------------+
| 1 |      D01    | 2012-01-01 |
| 1 |      D02    | 2015-01-01 |
| 1 |      D03    | 2018-01-01 |
| 1 |      D04    | 2019-01-01 |
| 2 |      D01    | 2010-01-01 |
| 2 |      D02    | 2012-01-01 |
| 3 |      D01    | 2008-01-01 |
| 3 |      D02    | 2010-01-01 |
| 3 |      D03    | 2012-01-01 |
| 4 |      D01    | 2015-01-01 |
| 4 |      D02    | 2017-01-01 |
+---+-------------+------------+

我知道这可以使用 LEAD OR LAG 函数来完成,但是谁能告诉我如何使用 Self Join 来做到这一点?

提前致谢!!

【问题讨论】:

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


    【解决方案1】:

    假设 ROW_NUMBER() 函数也不受限制,此查询使用实际的自联接:

    SELECT
        curr.Id,
        curr.Dept_name,
        curr.Hiredate,
        DATEADD(day, -1, next.Hiredate) AS Last_day
    FROM
    (
        SELECT *, ROW_NUMBER() OVER (PARTITION BY ID ORDER BY HireDate) AS RowNum
        FROM EmployeeHire
    ) AS curr
    LEFT OUTER JOIN
    (
        SELECT *, ROW_NUMBER() OVER (PARTITION BY ID ORDER BY HireDate) AS RowNum
        FROM EmployeeHire
    ) AS next
        ON curr.ID = next.ID AND curr.RowNum = next.RowNum - 1
    

    我不确定在没有 ROW_NUMBER() 函数的情况下按任意标准排序时如何进行自联接。

    【讨论】:

      【解决方案2】:

      您可以使用lead() 和日期算术:

      select
          t.*,
          dateadd(
              day, 
              -1, 
              lead(hiredate, 1, '2100-01-01') over(partition by id order by hiredate)
          ) last_day
      from mytable t
      

      lead() 的第二个参数是偏移量(这里,你想要“下一个”行,所以1),第三个是默认值,即为分区中的“最后一个”行返回.

      如果您想在没有窗口函数的情况下执行此操作,我建议使用横向连接或子查询:

      select t.*, x.last_day
      from mytable t
      cross apply (
          select dateadd(
              day, 
              -1, 
              coalesce(min(t1.hiredate), 2100-01-01')
          ) last_day
          from mytable t1
          where t1.id = t.id and t1.hiredate > t.hiredate
      )
      

      【讨论】:

      • 感谢您的回复,但我想使用 Self Join 来做到这一点。
      • @karandang:为什么?窗口函数是做你想做的最有效(也是最简单)的方法。
      • 我知道,但我想了解如何使用 Self Join 来完成。我在一次采访中被问到这个问题,所以想了解一下。
      • @karandang:好的。我提供了一个横向连接的解决方案。
      【解决方案3】:

      我认为通常我会选择一个窗口函数,但如果它不在表中并且您的数据没有太多列,那么结合分组的自联接看起来很干净:

      select      a.id, a.Dept_name, a.Hiredate, 
                  last_day = dateadd(day, -1, min(b.Hiredate))
      from        @hireData a
      left join   @hireData b on a.Id = b.Id and b.Hiredate > a.Hiredate
      group by    a.id, a.Dept_name, a.Hiredate
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-05-11
        • 1970-01-01
        • 1970-01-01
        • 2010-10-19
        • 1970-01-01
        相关资源
        最近更新 更多