2017-07-27 18 views
2

我有一個表使用位列跟蹤某個狀態。我想獲取狀態更改的第一個時間戳。我使用臨時表獲得了所需的輸出,但有沒有更好的方法來做到這一點?在列值中獲取更改的時間戳

我得到狀態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 
+0

你是否還希望第一條記錄的狀態= 1或只有0? – Siyual

+0

它總是1-> 0還是這些數字有所不同? –

+0

@Siyual只有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 
+0

感謝您的回答。我在找什麼只是1行,這是從1到0的最新狀態變化。你的答案給了我一個從1到0的每個狀態變化的行。感謝指向LAG(),非常整潔的函數。另外,分區非常緩慢。我有一張370多萬行的桌子,需要7分鐘以上,而我有臨時桌子的桌子需要12秒鐘。這是否有原因? –

+1

@inquisitive_mind完成所有更改後,不應該很難過濾掉最後一個。至於表演,那可以取決於很多事情,比如你桌上有什麼樣的索引,以及你的數據是如何分佈的。例如:成千上萬行中只有少量更改1> 0,還是每隔幾行進行切換。鑑於370m行的新信息,並且只需要最後一次更改,LAG()肯定不是一個好主意,因爲它必須通過所有行。 –

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的最新狀態是否爲1。包含iddt_create列的enabled列上的非聚簇索引可以提高查詢性能。

+0

它不起作用,因爲我正在尋找從1到0的最新狀態變化而不是前1個排序的asc –

+0

對不起,我忽略了id列。我已更正查詢,以便現在爲每個ID返回從1到0的最新狀態更改。它不使用臨時表來消除臨時表掃描並利用索引。我已經測試了它在420密耳行,並與該索引我設法縮短執行時間aprox。 8分鐘到22秒,而你臨時桌子的解決方案取得了進步。30分鐘在我的開發機器上執行。 –

+0

由於這種情況,這會產生不正確的結果sc.dt_create> MaxStatusChanges.max_dt_create不正確。條件應該是min(sc.dt_create)> MaxStatusChanges.max_dt_create,但不能在ON子句中使用聚合函數。 –