获取某个人在特定日期的最后一次操作

时间:2013-04-23 16:47:59

标签: sql sql-server greatest-n-per-group

我有一个包含以下行的表:

 NAME                        RFID                  ACTION    TIME       DATE

Kashif Islam            E2001026770D00742340248A    OUT  12:40:00   1/30/2013
Dr.Arshad Ali Shahid    E2001026770D0212267009D3    IN   13:52:00   1/30/2013
Qasim Mehmood           E2001026770D018223202774    IN   13:52:00   1/30/2013
M.Bilal Khan            E2001026770D009522402D80    IN   13:52:00   1/30/2013
Abdul Hameed            E2001026770D0181248019B8    IN   13:52:00   1/30/2013
Usman Tariq             E2001026770D00862570111D    IN   13:52:00   1/30/2013
Dr. Asif Gondal         E2001026770D012426600B32    IN   13:52:00   1/30/2013
Dr.Arshad Ali Shahid    E2001026770D0212267009D3    OUT  13:52:00   1/30/2013
Dr.Arshad Ali Shahid    E2001026770D0212267009D3    IN   13:53:00   1/30/2013
Dr.Arshad Ali Shahid    E2001026770D0212267009D3    OUT  13:53:00   1/30/2013
Dr.Arshad Ali Shahid    E2001026770D0212267009D3    IN   13:53:00   1/30/2013
Dr.Arshad Ali Shahid    E2001026770D0212267009D3    OUT  13:53:00   1/30/2013
Dr.Arshad Ali Shahid    E2001026770D0212267009D3    IN   13:54:00   1/30/2013
Dr.Arshad Ali Shahid    E2001026770D0212267009D3    OUT  13:54:00   1/30/2013
Aamir Hafeez            E2001026770D01952510155B    IN   13:55:00   1/30/2013
Amjad Ali Anjum         E2001026770D024125401476    IN   13:55:00   1/30/2013
Amjad Ali Anjum         E2001026770D024125401476    OUT  13:56:00   1/30/2013
Dr. Asif Gondal         E2001026770D012426600B32    OUT  13:56:00   1/30/2013
Arif Shah               E2001026770D01852370206D    IN   13:56:00   1/30/2013
Fida ul Hassan          E2001026770D02112720095C    IN   13:56:00   1/30/2013

现在我希望在每个人的指定日期获得最新的ACTION,例如:

    1/30/2013   13:56:00    OUT Amjad Ali Anjum
    1/30/2013   13:56:00    IN  Arif Shah
    1/30/2013   13:56:00    OUT Dr. Asif Gondal
    1/30/2013   13:54:00    OUT Dr.Arshad Ali Shahid
    1/30/2013   13:56:00    IN  Fida ul Hassan

我使用以下查询来获取它,但我得不到正确的结果:

WITH CTE AS (
SELECT 
   row_number() over (partition by personname order by date) rn,
   date,action,time,
   personname

FROM
   AISDb)
SELECT date,time,action,
       personname
FROM CTE WHERE RN = 1 AND datestamp = '1/30/2013'

3 个答案:

答案 0 :(得分:8)

我认为你的过滤器位于错误的位置,并且over()子句内的顺序都是错误的。

;WITH CTE AS (
  SELECT 
   row_number() over (partition by personname order by time DESC) rn,
   date,action,time,
   personname
FROM
   AISDb
WHERE datestamp = '20130130')
SELECT date,time,action,
       personname
FROM CTE WHERE RN = 1;

SQL fiddle demo

如果你需要在IN / OUT的情况下打破平局,两者同时记录,一种方法是打破平局,假设OUT发生在最后:

;WITH CTE AS (
  SELECT 
   row_number() over (partition by personname order by time DESC, action DESC) rn,
   date,action,time,
   personname
FROM
   AISDb
WHERE datestamp = '20130130')
SELECT date,time,action,
       personname
FROM CTE WHERE RN = 1;

SQL fiddle demo

答案 1 :(得分:2)

经典问题。一种可能的解决方案:

select w.* 
from w
inner join (
    select name, max(time) time
    from w
    where date = '2013-01-30'
    group by Name
) sel on w.Name = sel.Name 
     and w.Time = sel.Time
where w.date = '2013-01-30'

小猪背上亚伦的小提琴:http://sqlfiddle.com/#!3/335e4/11

一些注意事项:

  • 你应该真的有一个字段来保存日期和时间。过滤,索引,排序,这一切都更简单。
  • 如果你有一个TIE(同一个名字同时有两个交易),这个解决方案将带来两者。

答案 2 :(得分:-1)

由于人们的回答表明您需要将日期/时间逻辑的顺序更改为Desc,因此您将获得最新的第一个。另一件事是您只在CTE中按人名进行分区,因此无论日期如何,1值都将是最新值,然后您将日期限制在外部,因此您可能没有匹配的值。您可以通过几种方式解决此问题,但我只是将日期添加到分区逻辑中。

WITH    CTE AS 
(
        SELECT  row_number() over (partition by personname, [date]  order by [time] desc, rn desc) rn,
                [date],
                [action],
                [time],
                personname
        FROM   (Select  row_number() over (Order By (Select Null)) rn,
                        [date],
                        [action],
                        [time],
                        personname
                FROM    AISDb)
)
SELECT  [date],
        [action],
        [time],
        personname
FROM    CTE 
WHERE   RN = 1 
AND     datestamp = '1/30/2013'

为了绕过关系,我添加了一个嵌套表,它根据(Select Null)得到一个row_number。这是一个janky变通方法,将获得默认排序。如果这不起作用,则无法使用当前输入执行所需操作,并且应添加标识列以捕获插入顺序。