如何在SQL Server中查找当天的最新状态

时间:2017-02-09 01:34:44

标签: sql sql-server tsql

我有一个SQL Server问题,我试图在工作中弄清楚:

有一个状态字段的表格可以包含名为"参与的状态。"我只是试图找到记录,如果当天的最新状态是"参与"并且只有当状态在同一天从另一个状态更改为"参与。"

我不想要状态已经过的任何记录"参与。"它必须在同一天更改为该状态。您可以通过日期时间字段ChangedOn判断状态何时更改。

在下面的示例中,我只想带回ID 1880,因为"参与"有最新的时间戳。我不会带回ID 1700,因为最后一个记录是"其他,"我不会带回ID 1600,因为"参与"是那一天唯一的状态。

ChangedOn          Status            ID
02/01/17 15:23     Terminated        1880
02/01/17 17:24     Participated      1880
02/01/17 09:00     Other             1880
01/31/17 01:00     Terminated        1700
01/31/17 02:00     Participated      1700
01/31/17 03:00     Other             1700
01/31/17 02:00     Participated      1600

我在考虑使用Window功能,但我不知道如何开始使用它。自从我写完这样的查询以来,已经有几个月了,所以我有点不合时宜。

谢谢!

3 个答案:

答案 0 :(得分:0)

您可以使用窗口函数:

select t.*
from (select t.*,
             row_number() over (partition by cast(ChangedOn as date)
                                order by ChangedOn desc
                               ) as seqnum,
             sum(case when status <> 'Participate' then 1 else 0 end) over (partition by cast(ChangedOn as date)) as num_nonparticipate
      from t
     ) t
where (seqnum = 1 and ChangedOn = 'Participate') and
      num_nonparticipate > 0;

答案 1 :(得分:0)

尝试使用其他样本数据

declare @t table(ChangedOn datetime,Status varchar(50),ID int)
insert into @t VALUES
('02/01/17 15:23',     'Terminated'        ,1880)
,('02/01/17 17:24',     'Participated'      ,1880)
,('02/01/17 09:00',     'Other'             ,1880)
,('01/31/17 01:00',     'Terminated'        ,1700)
,('01/31/17 02:00',     'Participated'      ,1700)
,('01/31/17 03:00',     'Other'             ,1700)
,('01/31/17 02:00',     'Participated'      ,1600)

;

WITH CTE
AS (
    SELECT *
        ,row_number() OVER (
            PARTITION BY id
            ,cast(ChangedOn AS DATE) ORDER BY ChangedOn DESC
            ) AS seqnum
    FROM @t
    )
SELECT *
FROM cte c
WHERE seqnum = 1
    AND STATUS = 'Participated'
    AND EXISTS (
        SELECT id
        FROM cte c1
        WHERE seqnum > 1
            AND c.id = c1.id
        )

第二次查询,这是更好的

这里CTE是相同的

SELECT *
FROM cte c
WHERE seqnum = 1
AND STATUS = 'Participated'
AND EXISTS (
SELECT id
FROM cte c1
WHERE  STATUS != 'Participated'
    AND c.id = c1.id
)

答案 2 :(得分:0)

你能检查一下吗?

 WITH sample_table(ChangedOn,Status,ID)AS(
    SELECT CONVERT(DATETIME,'02/01/2017 15:23'),'Terminated',1880 UNION ALL
    SELECT '02/01/2017 17:24','Participated',1880 UNION ALL
    SELECT '02/01/2017 09:00','Other',1880 UNION ALL
    SELECT '01/31/2017 01:00','Terminated',1700 UNION ALL
    SELECT '01/31/2017 02:00','Participated',1700 UNION ALL
    SELECT '01/31/2017 03:00','Other',1700 UNION ALL
    SELECT '01/31/2017 02:00','Participated',1600
)
SELECT ID FROM (
SELECT *
      ,ROW_NUMBER()OVER(PARTITION BY ID,CONVERT(VARCHAR,ChangedOn,112) ORDER BY ChangedOn) AS rn
      ,COUNT(0)OVER(PARTITION BY ID,CONVERT(VARCHAR,ChangedOn,112)) AS cnt 
      ,CASE WHEN Status<>'Participated' THEN 1 ELSE 0 END AS ss
      ,SUM(CASE WHEN Status!='Participated' THEN 1 ELSE 0 END)OVER(PARTITION BY ID,CONVERT(VARCHAR,ChangedOn,112)) AS OtherStatusCnt
FROM sample_table
) AS t WHERE t.rn=t.cnt AND t.Status='Participated' AND t.OtherStatusCnt>0

- 返回: 1880