2014-03-24 35 views
1

我正在從數據庫中選擇句點列表。如果當前行是第一行則週期與日期開始,我能找到之間的間歇期開始是這樣的:查找當前行是否是從數據庫中選擇的最後一行

SELECT 
... 
CASE WHEN row_number() OVER(ORDER BY r.created_at ASC) = 1 THEN r.created_at - r.created_at::date ELSE NULL END AS period 
... 
FROM mytable r 

我怎樣才能做同樣的最後行?查找最後一行的r.created_at和其日期的午夜之間的時間。

我知道firstlast函數PostgreSQL(https://wiki.postgresql.org/wiki/First/last_(aggregate)),但它們是聚合函數,並沒有幫助在這種情況下。

編輯: 這個問題有2個很好的答案。他們都沒有幫助我,因爲我作爲我的問題的一部分提出的這條單線是更大的查詢的一部分,以編程方式放在一起,並且使用提供的解決方案將迫使我改變很多代碼,這是我不願意做的這點。如果縮放問題發生 - 那麼我肯定會重新考慮。

+1

如何使用'DESC'而不是'ASC'來執行相同的操作? –

+1

如果您通過(... DESC)排序,最後一行將是第一行... – joop

+0

嗯,這可能實際上工作。謝謝。我現在必須測試它:) –

回答

1

這可能比窗函數更快:

with r as (
    select 
     min(created_at) as min_created_at, 
     max(created_at) as max_created_at 
    from mytable 
) 
select 
    case when (select min_created_at from r) = created_at 
    then created_at - created_at::date else null 
    end as period_min, 
    case when (select max_created_at from r) = created_at 
    then created_at - created_at::date else null 
    end as period_max 
from mytable 
1

你可以在CASE語句中使用window functions first_value() and last_value()

SELECT * 
    , CASE WHEN ts IN (first_value(created_at) OVER w 
         , last_value(created_at) OVER w) 
     THEN created_at::time::interval ELSE NULL END AS period 
FROM tbl 
WINDOW w AS (ORDER BY created_at rows BETWEEN UNBOUNDED PRECEDING 
              AND UNBOUNDED FOLLOWING); 

這裏特殊的要求:你需要調整frame definition爲致電last_value()。默認情況下,它是:

RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW 

但是,你需要:

ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING 

first_value()通話將與默認框架的工作,但可以使用相同的爲好。

我也簡化了period的計算。您的定義與的time組件重合,只需投射到time即可「截斷」日期部分:created_at::time
鑄造到interval之後,它只是返回與原始查詢相同的數據類型。

由於窗口函數的當前實現,結果將自動訂購created_at。但不要依賴那個。如果您需要排序輸出,請明確添加到末尾:

ORDER BY created_at 
相關問題