PAYATHON 2026

如何在 DB2 中自动获取两个指定日期之间的数据

数据小陈

结论

可以。以 DB2 的 CURRENT DATE 为基准,先算出当月第一天,再据此确定上一个完整 billing cycle 的日期范围。

报表在 3 月 5 日运行时:

  • 起始日期:1 月 26 日
  • 结束日期:2 月 25 日
  • 时间戳筛选的排他上界:2 月 26 日

推荐写法

如果数据字段是 TIMESTAMP,建议采用左闭右开的范围,避免漏掉 2 月 25 日当天带有具体时间的数据:

WITH date_bounds AS
(
    SELECT
        month_start - 1 MONTH - 6 DAYS AS start_date,
        month_start - 3 DAYS           AS end_exclusive
    FROM
    (
        SELECT
            CURRENT DATE
                - (DAY(CURRENT DATE) - 1) DAYS AS month_start
        FROM SYSIBM.SYSDUMMY1
    ) AS x
)
SELECT t.*
FROM your_table AS t
CROSS JOIN date_bounds AS b
WHERE t.transaction_timestamp >= b.start_date
  AND t.transaction_timestamp <  b.end_exclusive;

假设查询在 3 月 5 日运行,各日期的计算结果为:

month_start  = 3 月 1 日
start_date   = 3 月 1 日 - 1 MONTH - 6 DAYS = 1 月 26 日
end_exclusive = 3 月 1 日 - 3 DAYS          = 2 月 26 日

实际查询范围是:

[1 月 26 日 00:00:00, 2 月 26 日 00:00:00)

这个范围完整覆盖了 1 月 26 日至 2 月 25 日的数据。

如果字段类型是 DATE

如果字段是纯 DATE 类型,也可以用 BETWEEN 包含起止日期:

WITH date_bounds AS
(
    SELECT
        month_start - 1 MONTH - 6 DAYS AS start_date,
        month_start - 4 DAYS           AS end_date
    FROM
    (
        SELECT
            CURRENT DATE
                - (DAY(CURRENT DATE) - 1) DAYS AS month_start
        FROM SYSIBM.SYSDUMMY1
    ) AS x
)
SELECT t.*
FROM your_table AS t
CROSS JOIN date_bounds AS b
WHERE t.transaction_date BETWEEN b.start_date AND b.end_date;

查询在 3 月运行时,两个边界分别是:

start_date = 1 月 26 日
end_date   = 2 月 25 日

也可以直接写在 WHERE 中

如果日期边界不需要复用,可以直接写进 WHERE:

SELECT *
FROM your_table
WHERE transaction_timestamp >=
      (
          CURRENT DATE
          - (DAY(CURRENT DATE) - 1) DAYS
          - 1 MONTH
          - 6 DAYS
      )
  AND transaction_timestamp <
      (
          CURRENT DATE
          - (DAY(CURRENT DATE) - 1) DAYS
          - 3 DAYS
      );

注意事项

  • 上述计算以报表固定在每月 5 日运行,并读取最近一个已经结束的 billing cycle 为前提。
  • CURRENT DATE 取 DB2 数据库服务器认定的当前日期。如果数据库服务器与业务所在地区的时区不同,需要确认跨月时是否会产生日期偏差。
  • 对于 TIMESTAMP 字段,不要写成:
BETWEEN start_date AND end_date

end_date 转成时间戳后通常是当天的 00:00:00,可能漏掉结束日白天的数据。使用 < end_exclusive 可以避免这个问题。

  • 日期范围应直接与数据列比较,不要在列上套用 DATE() 等函数。例如,优先使用:
transaction_timestamp >= b.start_date

不要写成:

DATE(transaction_timestamp) >= b.start_date

直接比较通常更有利于 DB2 使用日期或时间戳索引。

  • 如果 WebI 使用语义层对象或 Universe 查询,需要确认生成的 SQL 能否保留 CTE。如果不能,可以改用直接写在 WHERE 中的版本,或者在 Universe 中创建对应的日期过滤对象。

备注:内容仅供参考。