如何比较SQL中同一个表中的相同列?

时间:2017-03-31 09:15:01

标签: sql sql-server

假设我有一张包含以下记录的表

Name             Seq                  Join                     Resign
---------------- ---------------------------------------- ----------------------------
Joe              1                    2001-11-04 00:00:00.000  2005-03-31 00:00:00.000
Joe              2                    2005-04-01 00:00:00.000  NULL
Jane             1                    2011-12-04 00:00:00.000  2013-02-01 00:00:00.000
Jane             2                    2015-05-01 00:00:00.000  NULL
Jack             1                    2001-01-01 00:00:00.000  2002-01-01 00:00:00.000
Jack             2                    2002-01-02 00:00:00.000  2003-01-01 00:00:00.000
Jack             3                    2005-01-01 00:00:00.000  2006-01-01 00:00:00.000
Jack             4                    2006-01-02 00:00:00.000  NULL

所以我试图找出员工Join DateSeq代表雇佣号码,所以如果员工辞职并且稍后重新加入公司,Seq将会增加。但是当员工获得晋升或搬到另一个部门时,问题是Seq也会增加。

在我的情况下,Joe有2 Seq但他从未辞职,因为他的第二个加入日期=辞职日期+ 1.所以我的最终预期结果是

  • Joe,2001-11-04
  • Jane,2015-05-01
  • Jack,2005-01-01(因为他在第二次雇用后辞职)

知道如何在不循环的情况下获得此结果吗?

注意:Seq可以是1,2,3,4等等取决于每位员工的晋升或辞职/重新加入次数

杰克预期结果是2005-01-01,因为从第一名雇员到第二名雇员并不是真正的辞职,因为第二次雇用JoinDate =第一次雇用ResignDate + 1 2002-01-01 = 2002-01-02 + 1。但从第二次雇用到第三次雇用实际上是因为2003-01-01 != 2005-01-01 + 1而辞职。我希望这是有道理的。

3 个答案:

答案 0 :(得分:1)

我想你可以试试这个:

SELECT B.NAME, JJOIN  
FROM (SELECT *
    , LAG(DD1) OVER (PARTITION BY NAME ORDER BY RMAX) AS DD1_PREC
   FROM  
    (
    SELECT *
        , ROW_NUMBER() OVER (PARTITION BY NAME ORDER BY SEQ DESC) AS RMAX 
        , LEAD(RESIGN) OVER (PARTITION BY NAME ORDER BY SEQ DESC) AS PREC_RESIGN
        ,  DATEDIFF(dd,LEAD(RESIGN) OVER (PARTITION BY NAME ORDER BY SEQ DESC),JJOIN) AS DD1
    FROM TABLEX) A
    ) B
WHERE (RMAX =1 AND DD1>1 ) 
     OR (RMAX = 2 AND DD1_PREC<=1)

输出:

NAME                 JJOIN
-------------------- -----------------------
Jack                 2005-01-01 00:00:00.000
Jane                 2015-05-01 00:00:00.000
Joe                  2010-11-04 00:00:00.000

答案 1 :(得分:0)

这更容易理解

;WITH cte AS (
    SELECT  res.*, 
       --df = 0 if join and resign dates have difference greater than 1 else df = 1
                DATEDIFF(Day, IsNull(jn.Resign, res.JoinDate), res.JoinDate) df,
                ROW_NUMBER() OVER (PARTITION BY res.Name ORDER BY res.Name DESC) AS rn
    FROM    [dbo].[tblWarheat1990] res
        LEFT JOIN [dbo].[tblWarheat1990] jn ON res.JoinDate = DATEADD(day, 1, jn.Resign)
    )
    , gte as (
    SELECT  *, 
            ROW_NUMBER() OVER (partition by name ORDER BY rn DESC) AS minimum 
    FROM    cte 
    WHERE   df = 0)

    SELECT * FROM gte WHERE minimum = 1
    ORDER BY rn DESC

答案 2 :(得分:-1)

您希望前一天没有join日期的最长resign日期。

我会这样做:

select t.name, max(t.join)
from t left join
     t tprev
     on t.join = dateadd(day, 1, tprev.resign)
where t.prev.resign is null
group by name;

或者,您可以使用seqlag()

执行此操作
select name, max(join)
from (select t.*,
             lag(t.resign) over (partition by t.name order by t.seq) as prev_resign
      from t
     ) t
where prev_resign is null or prev_resign <> dateadd(day, -1, resign)
group by name;