generate_series() 可快速高效生成日期序列,適用于時間維度分析和填充缺失日期。1. 基本用法是通過指定起始日期、結束日期和步長生成連續日期序列,如每天生成一次日期;2. 可結合表使用,通過 left join 填充缺失日期,確保統計完整;3. 替代循環查詢,提升性能,避免低效逐條處理;4. 靈活控制步長,支持按小時、周等生成序列,適用于多種報表和任務場景。
用 GENERATE_SERIES() 快速生成日期序列,其實比寫循環要簡單得多,也高效很多。尤其在做時間維度分析、填充缺失日期這類任務時,這個函數非常實用。
1. 基本用法:指定起始和結束日期
GENERATE_SERIES() 的核心是生成一個連續的值序列,配合日期類型使用時,可以輕松構造出日期范圍。例如:
SELECT generate_series('2024-01-01'::date, '2024-01-10'::date, '1 day')::date;
這段語句會從 2024 年 1 月 1 日開始,每天生成一次日期,直到 1 月 10 日為止。
關鍵點在于三個參數:
- 起始日期
- 結束日期
- 步長(這里是 ‘1 day’)
你可以根據需要調整步長為 ‘7 days’、’1 month’ 等。
2. 結合表使用:填充缺失日期
有時候你可能會遇到這樣的問題:比如銷售數據中某些天沒有記錄,導致圖表或統計不完整。這時候可以用 GENERATE_SERIES() 先生成完整的日期列表,再 LEFT JOIN 到原始數據上。
舉個例子:
SELECT d.date, COALESCE(s.amount, 0) AS sales_amount FROM generate_series('2024-01-01', '2024-01-31', '1 day')::date AS d(date) LEFT JOIN sales s ON d.date = s.sale_date;
這樣就能把整個月的每一天都列出來,哪怕那天沒銷售,金額也顯示為 0。
3. 替代循環查詢:避免低效的逐條處理
在一些老舊的 sql 寫法中,有人喜歡用 while 循環或者遞歸 CTE 來生成日期序列,但那不僅代碼復雜,執行效率也不高。而 GENERATE_SERIES() 是集合操作,數據庫內部優化過,性能更好。
比如你想生成過去 30 天的日期,完全可以這么寫:
SELECT current_date - generate_series(0, 29) AS date_list;
這里利用了從 0 開始的數字序列,減去當前日期就得到了倒推的日期列表。
4. 靈活控制步長:不只是“一天一天來”
除了按天生成,你還可以按小時、周、甚至分鐘來控制步長。例如:
-- 每小時生成一次,共24次 SELECT generate_series(now(), now() + interval '23 hours', '1 hour') AS hourly; -- 每周生成一次,共四周 SELECT generate_series('2024-01-01', '2024-01-28', '1 week')::date;
這種靈活性讓它在報表周期設置、定時任務模擬等場景下也非常實用。
基本上就這些。用好 GENERATE_SERIES(),你會發現很多原本需要循環或臨時表的任務,都可以變得簡單又高效。