获取列值更改的时间戳

时间:2017-07-27 20:37:19

标签: sql sql-server

我有一个使用位列跟踪某个状态的表。我想得到状态更改的第一个时间戳。我使用临时表获得了所需的输出,但是有更好的方法吗?

我得到状态1的最大时间戳,然后我得到状态0的最小时间戳,如果状态0的最小时间戳大于状态1的最大时间戳,那么我将它包含在结果集中。

示例数据

123 0   2016-12-21 20:04:56.217
123 0   2016-12-21 19:00:28.980
123 0   2016-12-21 17:00:10.207 <-- Get this record because this is the latest status change from 1 to 0
123 1   2016-12-20 16:15:58.787
123 1   2016-12-20 16:11:36.523
123 1   2016-12-20 14:20:02.467
123 1   2016-12-20 13:57:57.623
123 0   2016-12-20 13:55:31.421 <-- This should not be included in the result even though it is a status change but since it is not the latest
123 1   2016-12-20 13:54:57.307
123 0   2016-12-19 12:23:46.103
123 0   2016-12-18 11:47:21.267

SQL

CREATE TABLE #temp_status_changed
(
   id VARCHAR(22) NOT NULL,
   enabled BIT NOT NULL,
   dt_create DATETIME NOT null
)
INSERT INTO #temp_status_changed
SELECT id,enabled,MAX(dt_create) FROM mytable WHERE enabled=1 
GROUP BY id,enabled

SELECT a.id,a.enabled,MIN(a.dt_create)  FROM mytable a 
JOIN #temp_status_changed b ON a.id=b.id
WHERE a.enabled=0 
GROUP BY a.id,a.enabled 
HAVING MIN(a.dt_create) > (SELECT dt_create FROM #temp_status_changed WHERE id=a.id)


DROP TABLE #temp_status_changed

2 个答案:

答案 0 :(得分:2)

有几种方法可以实现这一目标。

例如,使用LAG()函数,您始终可以获取之前的值并进行比较:

SELECT * FROM
(
    SELECT *, LAG(Enabled) OVER (PARTITION BY id ORDER BY dt_create) PrevEnabled 
    FROM YourTable
) x
WHERE Enabled = 0 AND PrevEnabled = 1

答案 1 :(得分:0)

没有窗口函数的另一种方法是:

SELECT
    sc.id,
    sc.enabled,
    dt_create = MIN(sc.dt_create)
FROM
    YourTable AS sc
    JOIN (
        SELECT 
            id,
            max_dt_create = MAX(dt_create)
        FROM
            YourTable
        WHERE
            enabled = 1
        GROUP BY
            id
    ) as MaxStatusChanges
    ON sc.id = MaxStatusChanges.id AND
       sc.dt_create > MaxStatusChanges.max_dt_create

GROUP BY
    sc.id,
    sc.enabled

如果该ID没有状态为1的行,则该查询不返回id的行,如果该id的最新状态为1,则enabled列上的非聚集索引包含iddt_create列可以提高查询效果。