2017-04-20 41 views
0

我在紅移數據庫中有一組記錄,每個記錄都有一個指示活動開始的時間戳和一個指示活動結束的時間戳。每分鐘計數重複次數作爲列存儲

timestamp_start  |timestamp_end 
2017-01-01 01:01:31 |2017-01-01 01:48:31 
2017-01-01 01:02:35 |2017-01-01 02:08:35 
2017-01-01 01:09:10 |2017-01-01 02:18:10 
2017-01-01 01:10:05 |2017-01-01 02:00:05 
2017-01-01 01:14:58 |2017-01-01 01:56:58 
2017-01-01 01:19:10 |2017-01-01 02:18:10 
2017-01-01 01:25:10 |2017-01-01 01:54:10 
2017-01-01 01:30:23 |2017-01-01 01:56:23 
2017-01-01 01:36:26 |2017-01-01 03:06:26 
2017-01-01 01:37:03 |2017-01-01 02:14:03 
2017-01-01 01:37:15 |2017-01-01 02:08:15 
2017-01-01 01:37:55 |2017-01-01 02:58:55 
2017-01-01 01:42:49 |2017-01-01 02:59:49 
2017-01-01 01:44:10 |2017-01-01 03:23:10 
2017-01-01 01:46:49 |2017-01-01 02:58:49 
2017-01-01 01:49:34 |2017-01-01 02:15:34 
2017-01-01 01:52:11 |2017-01-01 02:38:11 
2017-01-01 01:52:45 |2017-01-01 03:31:45 
2017-01-01 01:54:15 |2017-01-01 02:17:15 
2017-01-01 01:55:14 |2017-01-01 02:40:14 

它是一個簡單的方法用下面的計算每分鐘的新活動的發生:

select date_trunc('minute', timestamp_start) as minute, count(*) as count 
    from myTable 
    group by 1 

同樣計數的活動結束:

select date_trunc('minute', timestamp_end) as minute, count(*) as count 
    from myTable 
    group by 1 

然而,我如何計算每一分鐘內「正在進行」的活動[編輯:對於某個範圍內的每一分鐘]?即在分組01:01中我們有一個新的活動開始。在分鐘01:02我們又開始了一個新的活動,但從01:01 開始的活動尚未完成,因此當前活動的計數爲是兩個。相反,02:00的記錄數必須爲而非包括在該分鐘之前完成的4條記錄中的任何記錄。此外,解決方案還必須不「爆炸」數據,即將記錄加入到「已準備好」分鐘的不同表中,以提供記錄的多個副本,然後計算結果表的長度。

我已經嘗試以下操作:

SELECT 
    minute, 
    count(CASE WHEN timestamp_end > minute AND timestamp_start < minute) AS tmp 
     FROM (
      SELECT minute 
      FROM (
       (
        SELECT date_trunc('minute', timestamp_start) AS minute 
        FROM myTable 
        GROUP BY 1 
       ) 
       UNION ALL (
        SELECT date_trunc('minute', timestamp_end) AS minute 
        FROM myTable 
        GROUP BY 1 
       ) 
       ) s1 
      GROUP BY 1) 

但是我懷疑,我已經形成嚴重的情況下參數,可以很好地missusing它。然而,我也查看了窗口函數,但是我不能看到一個明顯的方法來計數,只包含「當前活動」記錄。

+0

不幸的是,您當前的查詢既有邏輯問題也有語法問題;所以你可能不得不回到繪圖板。第一個問題:您想如何確定輸出中包含哪些分鐘?每一分鐘在一定範圍內?每分鐘都有一個非零計數?其他...? –

+1

您能否根據您提供的樣本輸出向您的問題添加預期結果?您的描述非常詳盡,但恐怕還有一些誤解空間 –

+0

@MarkAdelsberger在某個範圍內的每一分鐘,將更新 – DaveRGP

回答

1

UPDATE - 另一項建議在年底的基礎上,斯蒂法諾賈尼尼的想法...


原始的想法

產生輸出一分鐘,你當然可以做一些事情像

select count(*) 
    from myTable 
where $minute between timestamp_start and timestamp_end 

從SQL的角度來看,說你希望在該事件的範圍內記錄每個分鐘的輸出行的每條記錄,但是也不希望按照分鐘列表「爆炸」數據,這有點矛盾。我假設你關心的是運行查詢的性能和/或資源使用情況;我認爲這對於足夠大的數據集可能是一個問題,但如果您尚未嘗試這種方法,可能還是值得的。

另一種選擇可能的工作

現在我在斯特凡諾賈尼尼的解答發表了評論,什麼他暗示不會相當的工作。但它確實提出了一種可能的方法:首先捕獲計數改變的分鐘,然後後處理以獲得每分鐘的值。

要獲得分鐘列表當計數可能改變

select distinct minute from (
    select date_trunc('minute', timestamp_start) as minute from my_table 
    union all 
    select dateadd('m', 1, date_trunc('minute', timestamp_start)) as minute from my_table 
) 

這可能給你一套小得多分鐘加入對錶的。

您可能可以通過使用外部聯接來獲得更多類似於他的查詢的內容(並執行某些操作以避免重複記錄;但沒有解決這個問題),但自聯接會導致相同級別的「數據爆炸」就像這個版本的原始方法。

有什麼可能是錯誤的,他的查詢,所以考慮一些爭議這一點:

這兩種方法都試圖限制針對其「爆炸」中的數據,然後嘗試統計數據對應的採樣時間到每個選定的樣本分鐘。

斯特凡諾選擇樣本的方式的功能性問題是他只挑選事件的開始時間。但實際上,計數也可以在事件結束時改變。因此,考慮

Start   Stop 
10:00   10:15 
10:05   10:20 

現在斯特凡諾的查詢將產生記錄10:00和10:05,而你必須插值用於任何其他分鐘。您將正確推斷10:00到10:04的值爲1,10:05到10:15的值爲2。但你會 10:16推斷值爲2,因爲該查詢並沒有告訴你在那個時候任何改變。這是錯誤的。

現在你可能增加查詢的更復雜性來說明這一點;但計數邏輯在他的版本中已經更爲間接/複雜(並且僅僅是因爲他列出了不同計數方法的權衡並不意味着他們中的任何一個都精確或適合於給定的目的)。或者你可以以簡單直接的方式做到這一點。


,如果沒有上能夠正常工作(或者你不想使用它的一些其他原因),那麼我不知道SQL是你需要這個工作的工具。也許一個迭代過幾分鐘並將計數累加到臨時表中的過程?或者如果數據庫和用戶之間有一個服務層(java或其他東西),那麼可能在那裏進行計數?

+0

謝謝,這也是我得出的結論,數據很大,目前的方法是'爆炸'。我的任務是'避免爆炸',儘管tbf我沒有受到限制工具我是新來的sql,並想確保我沒有忽略過某些東西 – DaveRGP

+1

你介意提供一個例子,這樣我的解決方案會失敗嗎? –

+1

@StefanoZanini:在你的第一個評論後會很高興討論,但在你的第二個?後,你自己。 –

0

我認爲這個任務可以通過一個自連接完成,左表的開始日期位於右側表的行的開始日期和結束日期之間。

select t1.timestamp_start, count(*) 
from test t1 
join test t2 
on  t1.timestamp_start >= t2.timestamp_start and 
     t1.timestamp_start < t2.timestamp_end 
group by t1.timestamp_start 

這工作得很好,但輸出是不是每分鐘的計數,但每個timestamp_start計數。從該字段提取分鐘提出了一個新問題:第37分鐘和第52分鐘有更多的一個任務開始在他們身上,你應該爲他們顯示什麼數量?

這是最大/最小選項

select date_trunc('minute', tt.timestamp_start), 
     max(tt.cnt) as max_cnt, /* this is probably the value you want */ 
     min(tt.cnt) as min_cnt 
from (
      select t1.timestamp_start, count(*) as cnt 
      from test t1 
      join test t2 
      on  t1.timestamp_start >= t2.timestamp_start and 
        t1.timestamp_start < t2.timestamp_end 
      group by t1.timestamp_start 
     ) tt 
group by date_trunc('minute', tt.timestamp_start) 

總和選項是更簡單的(請注意,下面的查詢給出了相同的結果與上面sum聚合的查詢,因爲分組條件是不太嚴格的):

select date_trunc('minute', t1.timestamp_start), count(*) 
from test t1 
join test t2 
on  t1.timestamp_start >= t2.timestamp_start and 
     t1.timestamp_start < t2.timestamp_end 
group by date_trunc('minute', t1.timestamp_start) 

你可以找到一個工作示例here; rextester沒有Redshift模擬器,但是SQL Server有執行相同任務的功能,所以沒什麼大不了的。

+1

通常不會產生預期的結果。不會產生第一個事件開始的記錄,或者沒有其他事件正在進行時開始的任何其他事件。會產生多個可能相互矛盾的記錄,其中記錄多個事件開始的分鐘數。 –

+1

第一個事件問題在第一個「join」條件中用'> ='而不是'>'來處理,而你指出的第二個問題在我的答案的第二部分中討論。你可以在鏈接上看到所有的查詢,我加了 –

+0

謝謝,我會測試,但同時你的意思是'總和選項更簡單'?我在代碼中看不到一筆款項。 – DaveRGP