简体   繁体   English

如何在SQL Server中使用rownumber获取匹配数据?

[英]How to get matching data using rownumber in SQL Server?

I am new to SQL Server and I don't know how to word this question. 我是SQL Server的新手,我不知道怎么说这个问题。 I have feeling this might be repeated. 我觉得这可能会重演。 If you know it please flag it as duplicate. 如果您知道,请将其标记为重复。 I will explain with data what I am trying to achieve 我将用数据解释我想要实现的目标

Table data - sometable 表数据- sometable

ID  TKID    Status    DateTimeStamp            RunMin
-----------------------------------------------------
215  6      Start   2009-10-29 09:48:14.243    NULL
261  6      Stop    2009-10-30 10:05:16.460    1457
356  6      Start   2009-11-03 14:11:05.097    NULL
357  6      Stop    2009-11-03 15:20:05.133    1526
358  6      Start   2009-11-03 16:14:45.863    NULL
574  19     Start   2009-11-12 13:12:11.827    NULL
575  19     Stop    2009-11-12 13:47:23.077    35
543 259     Start   2009-11-12 09:01:24.013    NULL 
620 259     Stop    2009-11-14 11:25:30.177    NULL 
623 259     Start   2009-11-14 16:47:32.913    NULL 
720 352     Start   2009-11-18 17:47:38.637    NULL 
730 352     Stop    2009-11-19 08:22:28.317    874  
773 352     Start   2009-11-20 10:00:11.320    NULL 
778 352     Stop    2009-11-20 11:51:59.853    985  
812 352     Start   2009-11-20 17:51:35.640    NULL 
813 352     Stop    2009-11-20 17:53:52.373    987  
822 352     Start   2009-11-23 08:13:23.030    NULL 
823 352     Stop    2009-11-23 08:17:33.063    991  
901 352     Start   2009-12-01 10:50:16.547    NULL 
910 352     Stop    2009-12-01 10:50:54.200    991  

Expected output: 预期产量:

ID  TKID    Status    DateTimeStamp            RunMin      
-----------------------------------------------------
358  6      Start   2009-11-03 16:14:45.863    NULL     
623 259     Start   2009-11-14 16:47:32.913    NULL 

So basically I want to get the record which has the start status but doesn't have the stop status. 所以基本上我想获得具有start状态但没有stop状态的记录。

Now What I tried .. 现在我尝试了什么..

I tried to use the ROW_NUMBER function as below, 我尝试使用ROW_NUMBER函数,如下所示,

;with cte as 
(
    select 
       *,
       ROW_NUMBER() OVER (PARTITION BY tkid 
                          ORDER BY tkid, DateTimeStamp) AS rn
    from Prog_Timer
)
SELECT * 
FROM 
   (SELECT * 
    FROM cte
    WHERE TkID IN (SELECT TkID
                   FROM cte 
                   GROUP BY TkID
                   HAVING COUNT(*)% 2 = 1)
) as d

It gives me result as 它给了我结果

And then try to get the tkid with the Odd count and for that tkid got the data. 然后尝试使用Odd计数得到tkid,并且tkid得到了数据。

ID  TKID    Status    DateTimeStamp            RunMin
-----------------------------------------------------
215  6      Start   2009-10-29 09:48:14.243    NULL
261  6      Stop    2009-10-30 10:05:16.460    1457
356  6      Start   2009-11-03 14:11:05.097    NULL
357  6      Stop    2009-11-03 15:20:05.133    1526
358  6      Start   2009-11-03 16:14:45.863    NULL
543 259     Start   2009-11-12 09:01:24.013    NULL 
620 259     Stop    2009-11-14 11:25:30.177    NULL 
623 259     Start   2009-11-14 16:47:32.913    NULL 

I don't know how to get the last row only from this output for each tkid select only the last start row. 我不知道如何从每个tkid这个输出中获取最后一行只选择最后一个开始行。 I think my approch is pretty complicated. 我认为我的approch非常复杂。 There has to be simple way to get what I want. 必须有简单的方法来获得我想要的东西。 If you have new approach feel free to post. 如果您有新方法,请随时发布。 If you have anything to add to my existing query feel free to post. 如果您有任何要添加到我现有查询的内容,请随时发布。 In case of confusion feel free to comment. 如果有困惑,请随意评论。

If you modify your ROW_NUMBER() PARTITION to order by DateTimeStamp desc , then the latest row for each tkid will be given rn=1 , thus giving you the latest status for each tkid . 如果您order by DateTimeStamp desc修改ROW_NUMBER() PARTITION以进行order by DateTimeStamp desc ,那么每个tkid的最新行将被赋予rn=1 ,从而为您提供每个tkid的最新状态。 You then simply have to SELECT rows where the rn = 1 and the Status = 'Start' to get your desired output: 然后你只需要SELECT rn = 1Status = 'Start'来获得你想要的输出:

select * from
(select 
   *,
   ROW_NUMBER() OVER (PARTITION BY tkid order by DateTimeStamp desc) as rn
from Prog_Timer
)
T
where 
T.rn = 1 -- the latest status for each tkid 
and T.Status = 'Start' -- returns only started and not stopped timers
-- if timer is stopped, t.Status will be 'Stop' in the latest row

Lot of ways to do this, one of them is below: 有很多方法可以做到这一点,其中之一是:

SELECT T.*
FROM SOMETABLE T
JOIN (SELECT MAX(DATETIMESTAMP) MAXTIME, TKID
    FROM SOMETABLE 
    GROUP BY TKID) SRC
        ON SRC.MAXTIME = T.DATETIMESTAMP AND SRC.TKID = T.TKID
WHERE T.STATUS = 'Start'

Depending on the actual data, you might want to get MAX(ID) instead, in case it's sometimes possible for a process to stop and start at the same time. 根据实际数据,您可能希望获得MAX(ID),以防有时进程可以停止并同时启动。 But of course, in case of updates it could be possible for older ID values to have newer timestamps. 但是,当然,在更新的情况下,旧ID值可能具有更新的时间戳。

I think this can show your results: 我想这可以显示你的结果:

select *
from Prog_Timer st
where st.[Status] = 'Start' And
    isnull((select min(sti.DateTimeStamp) from Prog_Timer sti  
            where sti.[Status] = 'Stop' And sti.TKId = st.TKId And sti.DateTimeStamp > st.DateTimeStamp )
        , cast('2999/12/29' as datetime)) 
    > 
    isnull((select min(stii.LogDateTime) from Prog_Timer stii 
            where stii.[Status] = 'Start' And stii.TKId = st.TKId And stii.DateTimeStamp > st.DateTimeStamp)
        , cast('2999/12/29' as datetime))

But I'm waiting for best answer ;). 但我在等待最好的答案;)。

how about this: 这个怎么样:

;with cte as 
(
    select *
         , MAX(DateTimeStamp) OVER (PARTITION BY tkid) AS maxDt
    from Prog_Timer
)
SELECT * 
FROM cte
WHERE DateTimeStamp=maxDt and Status='Start'

Try this query: 试试这个查询:

SELECT * 
FROM tableName 
WHERE Status = 'start' 
  AND ID NOT IN (SELECT ID 
                 FROM tableName 
                 WHERE Status = 'stop')

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM