2016-03-11 120 views
0

我在Amazon Redshift上使用PostgreSQL。基於條件獲取行

我的表是:

drop table APP_Tax; 
create temp table APP_Tax(APP_nm varchar(100),start timestamp,end1 timestamp); 
insert into APP_Tax values('AFH','2018-01-26 00:39:51','2018-01-26 00:39:55'), 
('AFH','2016-01-26 00:39:56','2016-01-26 00:40:01'), 
('AFH','2016-01-26 00:40:05','2016-01-26 00:40:11'), 
('AFH','2016-01-26 00:40:12','2016-01-26 00:40:15'), --row x 
('AFH','2016-01-26 00:40:35','2016-01-26 00:41:34') --row y 

預期輸出:

'AFH','2016-01-26 00:39:51','2016-01-26 00:40:15' 
    'AFH','2016-01-26 00:40:35','2016-01-26 00:41:34' 

我不得不比較備用記錄之間startendtime如果爲TimeDifference <10秒得到下一個記錄endtime到最後或最終記錄。

I,e datediff(seconds,2018-01-26 00:39:55,2018-01-26 00:39:56) Is <10 seconds 

我嘗試這樣做:

SELECT a.app_nm 
    ,min(a.start) 
    ,max(b.end1) 
FROM APP_Tax a 
INNER JOIN APP_Tax b 
    ON a.APP_nm = b.APP_nm 
     AND b.start > a.start 
WHERE datediff(second, a.end1, b.start) < 10 
GROUP BY 1 

它的工作原理,但在條件失敗,則不返回row y

+0

看起來像[在Redshift中編寫查詢(基於更新)](https://stackoverflow.com/questions/35941138/writing-a-query-in-redshift-based-on-update) –

+0

您有2018年和2016年的混合日期。基於類似的問題,我已將它們設置爲2016年。 –

回答

0

有兩個原因row y不返回是由於條件:

  • b.start > a.start意味着行永遠不會與自己一起
  • 本集團將每APP_nm值只有一條記錄返回,但所有行都具有相同的值。

但是,查詢中會有更多邏輯錯誤無法成功處理。例如,它如何知道「新」會話何時開始?

您尋求的邏輯可以在普通PostgreSQL中藉助DISTINCT ON函數實現,該函數在特定列中顯示每行輸入值一行。但是,Redshift不支持DISTINCT ON

一些可能的解決辦法:DISTINCT ON like functionality for Redshift

你尋求將使用編程語言(它可以遍歷結果和存儲變量),但很難申請到一個SQL查詢(其目的是要操作的是微不足道的輸出結果行)。我建議提取數據並通過一個簡單的腳本運行它(例如在Python中),然後可以輸出您尋求的開始&結束組合。

這是我以前成功實施的Hadoop Streaming function的極佳使用案例。它會將記錄作爲輸入,然後「記住」開始時間,並且只在滿足所需的結束邏輯時才輸出記錄。

0

聽起來就像你在做什麼是活動事件的「會話」。你可以使用Windows Functions來實現Redshift。

完整的解決方案可能是這樣的:

SELECT 
    start AS session_start, 
    session_end 
FROM (
     SELECT 
     start, 
     end1, 
     lead(end1, 1) 
     OVER (
      ORDER BY end1) AS session_end, 
     session_boundary 
     FROM (
       SELECT 
       start, 
       end1, 
       CASE WHEN session_switch = 0 AND reverse_session_switch = 1 
        THEN 'start' 
       ELSE 'end' END AS session_boundary 
       FROM (
        SELECT 
         start, 
         end1, 
         CASE WHEN datediff(seconds, end1, lead(start, 1) 
         OVER (
         ORDER BY end1 ASC)) > 10 
         THEN 1 
         ELSE 0 END AS session_switch, 
         CASE WHEN datediff(seconds, lead(end1, 1) 
         OVER (
         ORDER BY end1 DESC), start) > 10 
         THEN 1 
         ELSE 0 END AS reverse_session_switch 
        FROM app_tax 
        ) 
       AS sessioned 
       WHERE session_switch != 0 OR reverse_session_switch != 0 
       UNION 
       SELECT 
       start, 
       end1, 
       'start' 
       FROM (
        SELECT 
         start, 
         end1, 
         row_number() 
         OVER (PARTITION BY APP_nm 
         ORDER BY end1 ASC) AS row_num 
        FROM APP_Tax 
        ) AS with_row_number 
       WHERE row_num = 1 
      ) AS with_boundary 
    ) AS with_end 
WHERE session_boundary = 'start' 
ORDER BY start ASC 
; 

這裏是breadkdown(子查詢名稱):

  1. sessioned - 我們首先確定開關行(出和)時,結束與開始之間的持續時間超過限制的行。
  2. with_row_number - 只是一個補丁來提取第一行,因爲沒有開關進去(還有就是我們記錄爲「開始」隱式開關)
  3. with_boundary - 然後我們確定哪些特定交換機發生行。如果你自己運行子查詢,很明顯,會話在session_switch = 0 AND reverse_session_switch = 1時開始,並在相反情況發生時結束。所有其他行都在會話中間,因此被忽略。
  4. with_end - 最後,我們結合「開始」 /「結束」行到(從而確定會話持續時間)結束/開始,並刪除結束行

with_boundary子查詢回答您最初的問題,但通常你會想結合這些行來獲得最後的結果,即會話持續時間。