You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PostgreSQL日期表迭代与每月工作日累计计数视图创建求助

解决PostgreSQL日期表迭代与工作日累计视图的需求

嘿,这两个需求其实都不用存储过程就能搞定,PostgreSQL的日期函数和窗口函数完全能胜任,我给你分步拆解:

1. 计算每个月的总工作日数

核心思路是先生成目标日期范围,筛选出周一到周五的日期(排除周末),再按月份分组统计数量。如果需要考虑节假日,还可以结合自定义节假日表扩展。

基础版本(仅排除周末)

-- 统计2024年每个月的工作日数量
SELECT
    DATE_TRUNC('month', date_col) AS month_start,
    COUNT(*) AS total_workdays
FROM
    GENERATE_SERIES('2024-01-01'::DATE, '2024-12-31'::DATE, '1 day'::INTERVAL) AS date_col
WHERE
    -- 排除周日(0)和周六(6)
    EXTRACT(DOW FROM date_col) NOT IN (0, 6)
GROUP BY
    DATE_TRUNC('month', date_col)
ORDER BY
    month_start;

扩展版本(排除周末+自定义节假日)

假设你有一张holidays表,包含holiday_date字段存储节假日日期:

SELECT
    DATE_TRUNC('month', d.date_col) AS month_start,
    COUNT(*) AS total_workdays
FROM
    GENERATE_SERIES('2024-01-01'::DATE, '2024-12-31'::DATE, '1 day'::INTERVAL) AS d(date_col)
LEFT JOIN
    holidays h ON d.date_col = h.holiday_date
WHERE
    EXTRACT(DOW FROM d.date_col) NOT IN (0, 6)
    -- 排除存在于节假日表的日期
    AND h.holiday_date IS NULL
GROUP BY
    DATE_TRUNC('month', d.date_col)
ORDER BY
    month_start;

2. 创建带每月重置工作日累计的视图

这个需求用窗口函数SUM()就能实现,核心是按月份分区,对工作日标记为1、非工作日标记为0,然后累计求和——这样非工作日时累计值不会递增,且每个月自动重置计数。

基础视图(仅排除周末)

CREATE OR REPLACE VIEW monthly_workday_counter AS
SELECT
    date_col AS current_date,
    -- 标记当前日期是否为工作日
    CASE
        WHEN EXTRACT(DOW FROM date_col) NOT IN (0, 6) THEN 1
        ELSE 0
    END AS is_workday,
    -- 按月份分区,累计工作日计数
    SUM(CASE
        WHEN EXTRACT(DOW FROM date_col) NOT IN (0, 6) THEN 1
        ELSE 0
    END) OVER (
        PARTITION BY DATE_TRUNC('month', date_col)
        ORDER BY date_col
        ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
    ) AS monthly_workday_accumulator
FROM
    GENERATE_SERIES('2024-01-01'::DATE, '2024-12-31'::DATE, '1 day'::INTERVAL) AS date_col;

扩展视图(排除周末+自定义节假日)

CREATE OR REPLACE VIEW monthly_workday_counter_with_holidays AS
WITH date_range AS (
    -- 生成目标日期范围
    SELECT GENERATE_SERIES('2024-01-01'::DATE, '2024-12-31'::DATE, '1 day'::INTERVAL) AS date_col
),
workday_flags AS (
    -- 标记每个日期是否为工作日(排除周末和节假日)
    SELECT
        d.date_col,
        CASE
            WHEN EXTRACT(DOW FROM d.date_col) NOT IN (0, 6)
                 AND NOT EXISTS (SELECT 1 FROM holidays h WHERE h.holiday_date = d.date_col)
            THEN 1
            ELSE 0
        END AS is_workday
    FROM date_range d
)
SELECT
    date_col AS current_date,
    is_workday,
    -- 按月份分区累计工作日计数
    SUM(is_workday) OVER (
        PARTITION BY DATE_TRUNC('month', date_col)
        ORDER BY date_col
        ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
    ) AS monthly_workday_accumulator
FROM workday_flags;

关键说明

  • PARTITION BY DATE_TRUNC('month', date_col):确保每个月的累计计数独立,到下一个月自动重置为0开始累计。
  • ORDER BY date_col:保证日期按顺序排列,累计结果符合时间逻辑。
  • SUM(is_workday):只有当is_workday为1(工作日)时,累计值才会递增,非工作日时保持上一个累计值不变。

内容的提问来源于stack exchange,提问作者MacAnRiogh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 08:34:14