结果不止一个的最新结果

时间:2017-03-19 13:08:43

标签: sql-server

我的表存储时钟输出时间,但其中一些会打出超过1次。如何获得结果不止一个的最新结果?

SELECT 
    ROW_NUMBER() OVER (PARTITION BY l.USERID, day(l.CHECKTIME), DATEPART(hh, l.CHECKTIME) ORDER BY (select 0)) RN, 
    l.USERID,
    CASE 
       WHEN CAST(l.CHECKTIME AS TIME) > = CAST(SC.EndTime AS TIME) 
          THEN CONVERT(VARCHAR(10), CAST(l.CHECKTIME AS TIME), 100)
          ELSE 'Early ClockOut ' + CONVERT(VARCHAR(100), CAST(l.CHECKTIME AS TIME), 100) 
    END as ClockOut,l.CHECKTIME
FROM
    CHECKINOUT l
INNER JOIN  
    USERINFO u ON l.USERID = u.USERID
INNER JOIN 
    UserUsedSClasses uuc ON uuc.USERID = u.USERID
INNER JOIN 
    SchClass SC ON uuc.SchId = SC.schClassid
WHERE 
    u.BADGENUMBER not in (79,103,78) 
    AND MONTH(CHECKTIME) = MONTH(getdate()) AND YEAR(CHECKTIME) = YEAR(getdate())
    AND uuc.SchId = 1
    AND DATEPART (hh, l.CHECKTIME) >= DATEPART(hh, SC.EndTime)
    AND DATEPART(hh, l.CHECKTIME) >= DATEPART (hh, SC.StartTime) 
ORDER BY 
    u.BADGENUMBER

输出:

RN  USERID  ClockOut    CHECKTIME
1   6       7:04PM      2017-03-09 19:04:12.000 
2   6       7:55PM      2017-03-09 19:55:59.000  
1   6       11:31PM     2017-03-09 23:31:27.000 

应仅显示此结果:

RN  USERID  ClockOut    CHECKTIME
-----------------------------------------------
1   6       11:31PM     2017-03-09 23:31:27.000 

1 个答案:

答案 0 :(得分:2)

row_number()中,将order by更改为l.CHECKTIME desc,然后使用common table expression或子查询过滤where rn = 1

要每天获取最新结帐,请将partition by更改为l.userid, dateadd(day, datediff(day, 0, l.checktime), 0),将日期时间截断为日期(您也可以使用convert(date,l.checktime))。

使用common table expression

;with cte as (
  select 
      rn = row_number() over (
        partition by l.userid, dateadd(day, datediff(day, 0, l.checktime), 0)
        order by l.checktime desc
      )
    , l.userid
    , Clockout = case 
        when cast(l.checktime as time) >= cast(sc.EndTime as time)
          then convert(varchar(100), cast(l.checktime as time), 100)
        else 'Early ClockOut ' + convert(varchar(100), cast(l.checktime as time), 100)
        end
    , l.checktime
    , u.badgenumber
  from checkinout l
    inner join userinfo u
      on l.userid = u.userid
    inner join UserUsedsclasses uuc
      on uuc.userid = u.userid
    inner join SchClass sc
      on uuc.SchId = sc.schClassid
  where uuc.SchId = 1
    and u.badgenumber not in (79, 103, 78)
    and l.checktime >= dateadd(month, datediff(month, 0, getdate() )  , 0)
    and l.checktime <  dateadd(month, datediff(month, 0, getdate() )+1, 0)
    and datepart(hour, l.checktime) >= datepart(hour, sc.EndTime)
    and datepart(hour, l.checktime) >= datepart(hour, sc.StartTime)
)
select *
from cte
where rn = 1
order by badgenumber;

或没有cte

select *
from (
  select 
      rn = row_number() over (
        partition by l.userid, dateadd(day, datediff(day, 0, l.checktime), 0)
        order by l.checktime desc
      )
    , l.userid
    , Clockout = case 
        when cast(l.checktime as time) >= cast(sc.EndTime as time)
          then convert(varchar(100), cast(l.checktime as time), 100)
        else 'Early ClockOut ' + convert(varchar(100), cast(l.checktime as time), 100)
        end
    , l.checktime
    , u.badgenumber
  from checkinout l
    inner join userinfo u
      on l.userid = u.userid
    inner join UserUsedsclasses uuc
      on uuc.userid = u.userid
    inner join SchClass sc
      on uuc.SchId = sc.schClassid
  where uuc.SchId = 1
    and u.badgenumber not in (79, 103, 78)
    and l.checktime >= dateadd(month, datediff(month, 0, getdate() )  , 0)
    and l.checktime <  dateadd(month, datediff(month, 0, getdate() )+1, 0)
    and datepart(hour, l.checktime) >= datepart(hour, sc.EndTime)
    and datepart(hour, l.checktime) >= datepart(hour, sc.StartTime)
  ) as sub
where rn = 1
order by badgenumber;

更快的执行方式:

AND MONTH(CHECKTIME) = MONTH(getdate()) 
AND YEAR(CHECKTIME)  = YEAR(getdate())

and l.checktime >= dateadd(month, datediff(month, 0, getdate() )  , 0) /* month start*/
and l.checktime <  dateadd(month, datediff(month, 0, getdate() )+1, 0) /* next month start */