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

在BigQuery标准SQL中实现通用周级历史记录查询

灵活查询指定表当日及过去N周对应星期几的记录数

我有一张审计表(包含tabnm、rundt和rec_cnt字段),存储了5年的数据,示例数据如下:

tabnm | rundt      | rec_cnt
emp   | 2025/04/22 | 100
emp   | 2025/04/21 | 110
emp   | 2025/04/20 | 96
....
emp   | 2025/04/16 | 117
emp   | 2025/04/15 | 156
....
emp   | 2025/04/10 | 176
emp   | 2025/04/09 | 160
emp   | 2025/04/08 | 154
emp   | 2025/04/07 | 182
....

需求很明确:检索指定表当日及过去N周对应星期几的记录数。比如今日是4月22日(周二),要返回4月22日、4月15日(上周二)、4月8日(上上周二)的数据,预期输出:

tabnm | rundt      | rec_cnt
emp   | 2025/04/22 | 100
emp   | 2025/04/15 | 156
emp   | 2025/04/08 | 154

目前用多个UNION ALL硬编码的方案不够灵活,调整周数时得修改代码;存储过程虽可行,但更想找纯SQL的通用方案,以下是几种优化思路:


方案1:递归CTE生成目标日期列表

递归CTE能动态生成过去N周的对应日期,再和审计表关联,适配大多数支持递归的数据库(MySQL 8+、PostgreSQL、BigQuery等):

WITH RECURSIVE date_range AS (
    -- 初始行:当前日期
    SELECT CURRENT_DATE() AS target_date
    UNION ALL
    -- 递归生成过去N周的日期,这里N=3,直接改数字就能调整周数
    SELECT DATE_SUB(target_date, INTERVAL 7 DAY)
    FROM date_range
    WHERE target_date > DATE_SUB(CURRENT_DATE(), INTERVAL 3*7 DAY)
)
SELECT a.tabnm, a.rundt, a.rec_cnt
FROM audit_tbl a
JOIN date_range d ON a.rundt = d.target_date
WHERE a.tabnm = 'emp'
ORDER BY a.rundt DESC;

如果要支持动态传参(比如MySQL中),可以用变量:

SET @N = 5; -- 要查询过去5周的数据

WITH RECURSIVE date_range AS (
    SELECT CURRENT_DATE() AS target_date
    UNION ALL
    SELECT DATE_SUB(target_date, INTERVAL 7 DAY)
    FROM date_range
    WHERE target_date > DATE_SUB(CURRENT_DATE(), INTERVAL @N*7 DAY)
)
SELECT a.tabnm, a.rundt, a.rec_cnt
FROM audit_tbl a
JOIN date_range d ON a.rundt = d.target_date
WHERE a.tabnm = 'emp'
ORDER BY a.rundt DESC;

方案2:用序列生成函数直接生成日期

部分数据库自带序列生成函数,代码更简洁:

PostgreSQL版本

SELECT a.tabnm, a.rundt, a.rec_cnt
FROM audit_tbl a
JOIN (
    -- generate_series(0,2) 表示0(当日)到2(过去2周),共3个日期
    SELECT CURRENT_DATE() - INTERVAL '7 days' * n AS target_date
    FROM generate_series(0, 2) n
) d ON a.rundt = d.target_date::date
WHERE a.tabnm = 'emp'
ORDER BY a.rundt DESC;

BigQuery版本

SELECT a.tabnm, a.rundt, a.rec_cnt
FROM audit_tbl a
JOIN (
    -- GENERATE_ARRAY(0,2) 生成0到2的数组,对应3个日期
    SELECT DATE_SUB(CURRENT_DATE(), INTERVAL 7*n DAY) AS target_date
    FROM UNNEST(GENERATE_ARRAY(0, 2)) n
) d ON a.rundt = d.target_date
WHERE a.tabnm = 'emp'
ORDER BY a.rundt DESC;

方案3:用日期属性直接过滤

利用日期的星期属性,筛选出和当日星期相同、且日期差为7的倍数的记录,同时限制时间范围在过去N周内:

SELECT tabnm, rundt, rec_cnt
FROM audit_tbl
WHERE tabnm = 'emp'
  -- 匹配星期几,注意不同数据库函数有差异
  AND DAYOFWEEK(rundt) = DAYOFWEEK(CURRENT_DATE())
  -- 限制在过去3周内
  AND rundt >= DATE_SUB(CURRENT_DATE(), INTERVAL 3*7 DAY)
  AND rundt <= CURRENT_DATE()
ORDER BY rundt DESC;

注意:不同数据库的星期函数不同,需适配:

  • MySQL: DAYOFWEEK()(1=周日,2=周一…7=周六)
  • PostgreSQL: EXTRACT(DOW FROM date)(0=周日,1=周一…6=周六)
  • BigQuery: EXTRACT(DAYOFWEEK FROM date)(1=周日,2=周一…7=周六)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 09:07:11