2013-01-02 113 views
0

我有一個表與結構SQL查詢:基於複雜的業務邏輯

id, timestamp, deviceId, datatype, measure 

柱度量的值表示的數據類型的值。例如,當處理開始時,數據類型是19並且是度量1.當數據類型完成時,數據類型仍然是19,其值爲0,並且新行插入具有相同時間戳,數據類型54和值作爲某個值。這意味着系統在完成時調用某個觸發器來更新此表。下面

1001, 2013-01-02 09:20:00, 501, 19, 1 
1005, 2013-01-02 10:00:00, 501, 19, 0 
1006, 2013-01-02 10:00:00, 501, 54, 65 

時間戳的1005 & 1006是相同的數據。例如,1001時間戳總是比的1005

1011, 2013-01-02 09:20:00, 601, 19, 1 
1015, 2013-01-02 10:00:00, 601, 19, 0 
1016, 2013-01-02 10:00:00, 601, 54, 105 

時間戳的1015 & 1016是相同更少,1011時間戳總是小於即1015

1021, 2013-01-02 09:20:00, 701, 19, 1 
1022, 2013-01-02 10:00:00, 701, 19, 0 
1023, 2013-01-02 10:00:00, 701, 54, 81 

時間戳的1022 & 1023一樣,1021時間戳總是小於比1022

對於多個設備可以同時發生同樣的過程。

現在的要求是找到的開始和結束時間,每完成交易就像

1006, 2013-01-02 09:20:00, 2013-01-02 10:20:00, 501, 65 
1016, 2013-01-02 09:20:00, 2013-01-02 10:20:00, 601, 105 
1023, 2013-01-02 09:20:00, 2013-01-02 10:20:00, 701, 81 

我經過約5年,完全被卡住編寫SQL查詢。任何指針/建議將不勝感激。

在此先感謝

+0

如何識別每個「交易」?這隻能通過檢查deviceId來實現嗎?每臺設備是否只能同時進行一項交易? – Flimzy

+0

每個完成的事務由數據類型54標識,如果數據類型54存在,則必須分別具有數據類型19值1和0的開始和結束時間。是的,每個設備一次只能有一個事務。同一臺設備可以在一天中進行多次交易。 – Atique

+0

是否每個事務都以'19開始,並以最高編號的數據類型結束? IOW:只需查看數據類型,在訂購{通過device_id,timestamp,id}時是否可以使用「鋸齒」檢測器?如果每層只有一條記錄,會發生什麼情況?如果層中有同一個{device_id,datatype}的多條記錄,會發生什麼情況?順便說一句:主鍵有幫助。 – wildplasser

回答

0

這是可能的,我在這裏簡化了這個問題,但我沒有看到任何理由爲什麼對於數據類型爲54的每條記錄,您不能只訪問數據類型爲19的設備的上一條記錄,措施1:

SELECT result.ID, 
     result.DeviceID, 
     MAX(start.Timestamp) StartTime, 
     result.Timestamp EndTime, 
     result.Measure 
FROM T result 
     INNER JOIN T start 
      ON start.DeviceID = result.DeviceID 
      AND start.Timestamp < result.Timestamp 
      AND start.DataType = 19 
      AND start.Measure = 1 
WHERE result.DataType = 54 
GROUP BY result.ID, result.DeviceID, result.Timestamp, result.Measure 

唯一真正的區別是,而不是試圖通過啓動之初和工​​作着的結果來解決這個問題,我已經開始與結果和向後努力的開始。如果同一設備的進程同時運行(即一個交易在前一個交易結束之前開始),則這將失敗

+0

該進程不能同時運行相同的設備和您的查詢工作相當不錯。 – Atique

2

SQL Fiddle

CREATE TABLE t 
     (id int, ts timestamp, deviceId int, datatype int, measure int) 
; 

INSERT INTO t 
     (id, ts, deviceId, datatype, measure) 
VALUES 
     (1001, '2013-01-02 09:20:00', 501, 19, 1), 
     (1005, '2013-01-02 10:00:00', 501, 19, 0), 
     (1006, '2013-01-02 10:00:00', 501, 54, 65), 
     (1007, '2013-01-02 10:20:00', 501, 19, 1), 
     (1008, '2013-01-02 11:00:00', 501, 19, 0), 
     (1009, '2013-01-02 11:00:00', 501, 54, 65), 
     (1011, '2013-01-02 09:20:00', 601, 19, 1), 
     (1015, '2013-01-02 10:00:00', 601, 19, 0), 
     (1016, '2013-01-02 10:00:00', 601, 54, 105), 
     (1021, '2013-01-02 09:20:00', 701, 19, 1), 
     (1022, '2013-01-02 10:00:00', 701, 19, 0), 
     (1023, '2013-01-02 10:00:00', 701, 54, 81) 
; 

with parted as (
    select floor((rn - 1)/2.0) p, * 
    from (
     select 
      row_number() over (partition by deviceId order by ts, datatype) rn, 
      id, ts, deviceId, dataType, measure 
     from t 
     where not(datatype = 19 and measure = 0) 
    ) s 
) 
select 
    p1.id, p0.ts "start", p1.ts "end", p1.deviceId, p1.measure 
from 
    parted p0 
    inner join 
    parted p1 on 
     p0.deviceId = p1.deviceId 
     and p0.p = p1.p 
     and p0.datatype = 19 and p1.datatype = 54 
order by p1.id 
; 
    id |  start  |   end   | deviceid | measure 
------+---------------------+---------------------+----------+--------- 
1006 | 2013-01-02 09:20:00 | 2013-01-02 10:00:00 |  501 |  65 
1009 | 2013-01-02 10:20:00 | 2013-01-02 11:00:00 |  501 |  65 
1016 | 2013-01-02 09:20:00 | 2013-01-02 10:00:00 |  601 |  105 
1023 | 2013-01-02 09:20:00 | 2013-01-02 10:00:00 |  701 |  81 
+0

這個不錯的技巧確實奏效。謝謝你Clodoaldo – Atique

0

我對這個邏輯是簡單的聚合。但是,聚合鍵是具有數據類型54的「下一個」記錄,具有相同的設備ID。

爲了得到這個下一個記錄,我使用的是相關子查詢的where子句中:

select next54 as id, MIN(timestamp) as starttime, MAX(timestamp) as endtime, MAX(device_id) as device_id, 
     MAX(case when id = next54 then measure end) 
from (select t.*, 
      (select MIN(id) from t t2 where t2.id >= t.id and t2.datatype = 54 and t2.device_id = t.device_id) as next54 
     from t 
    ) t 
group by next54 

剩下的就是聚集。

因爲我個人不相關子查詢的忠實粉絲,你也可以在此使用窗口函數寫(有時稱爲解析函數中的Oracle):

select next54 as id, MIN(timestamp) as starttime, MAX(timestamp) as endtime, MAX(device_id) as device_id, 
     MAX(case when id = next54 then measure end) 
from (select t.*, 
      min(id54) over (partition by device_id order by id desc) as next54 
     from (select t.*, 
        (case when datatype = 54 then id end) as id54 
      from t 
      ) t 
    ) t 
group by next54 

min功能與order by條款做了「累計」最低。結果應該與相關的子查詢相同。

+0

使用lead()函數可以更高效地訪問* next *記錄,而不是使用共同相關的子查詢。 –

+0

我不想要「下一個」記錄。我想要數據類型爲54的下一條記錄(具有相同的設備ID)。另外,哪種更高效取決於Oracle如何優化查詢。 –

+0

這個問題被標記爲PostgreSQL,而不是Oracle。但是在兩個系統上,使用窗口函數通常比使用共同相關的子查詢要快,因爲大部分時間只執行一次(表格)掃描(而不是兩次)。 –