如何在 SQL 服务器中使用 rownumber 获取匹配数据?
How to get matching data using rownumber in SQL Server?
我是 SQL 服务器的新手,我不知道如何表达这个问题。我觉得这可能会重复。如果您知道,请将其标记为重复。我会用数据来解释我想要实现的目标
Table 数据 - 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
预期输出:
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
所以基本上我想获得具有 start
状态但没有 stop
状态的记录。
现在我尝试了什么..
我尝试使用下面的 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
它给我的结果是
然后尝试获取具有 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
我不知道如何只从这个输出中获取最后一行 tkid
select 只有最后一行。我认为我的方法很复杂。必须有简单的方法来获得我想要的东西。如果您有新方法,请随时 post。如果您有任何要添加到我现有查询中的内容,请随时 post。如有困惑,请随时发表评论。
试试这个查询:
SELECT *
FROM tableName
WHERE Status = 'start'
AND ID NOT IN (SELECT ID
FROM tableName
WHERE Status = 'stop')
如果您将 ROW_NUMBER() PARTITION
修改为 order by DateTimeStamp desc
,则每个 tkid
的最新行将被提供 rn=1
,从而为您提供每个 tkid
。然后,您只需 SELECT
行 rn = 1
和 Status = '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
有很多方法可以做到这一点,下面是其中之一:
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'
根据实际数据,您可能希望改为获取 MAX(ID),以防进程有时可能同时停止和启动。但是当然,在更新的情况下,旧的 ID 值可能有更新的时间戳。
我认为这可以显示您的结果:
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))
但我正在等待最佳答案 ;)。
这个怎么样:
;with cte as
(
select *
, MAX(DateTimeStamp) OVER (PARTITION BY tkid) AS maxDt
from Prog_Timer
)
SELECT *
FROM cte
WHERE DateTimeStamp=maxDt and Status='Start'
我是 SQL 服务器的新手,我不知道如何表达这个问题。我觉得这可能会重复。如果您知道,请将其标记为重复。我会用数据来解释我想要实现的目标
Table 数据 - 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
预期输出:
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
所以基本上我想获得具有 start
状态但没有 stop
状态的记录。
现在我尝试了什么..
我尝试使用下面的 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
它给我的结果是
然后尝试获取具有 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
我不知道如何只从这个输出中获取最后一行 tkid
select 只有最后一行。我认为我的方法很复杂。必须有简单的方法来获得我想要的东西。如果您有新方法,请随时 post。如果您有任何要添加到我现有查询中的内容,请随时 post。如有困惑,请随时发表评论。
试试这个查询:
SELECT *
FROM tableName
WHERE Status = 'start'
AND ID NOT IN (SELECT ID
FROM tableName
WHERE Status = 'stop')
如果您将 ROW_NUMBER() PARTITION
修改为 order by DateTimeStamp desc
,则每个 tkid
的最新行将被提供 rn=1
,从而为您提供每个 tkid
。然后,您只需 SELECT
行 rn = 1
和 Status = '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
有很多方法可以做到这一点,下面是其中之一:
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'
根据实际数据,您可能希望改为获取 MAX(ID),以防进程有时可能同时停止和启动。但是当然,在更新的情况下,旧的 ID 值可能有更新的时间戳。
我认为这可以显示您的结果:
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))
但我正在等待最佳答案 ;)。
这个怎么样:
;with cte as
(
select *
, MAX(DateTimeStamp) OVER (PARTITION BY tkid) AS maxDt
from Prog_Timer
)
SELECT *
FROM cte
WHERE DateTimeStamp=maxDt and Status='Start'