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

如何用SQL计算2022年及以后的12个月滚动活跃客户数?

问题描述

我有一张包含order_date和customer_id字段的orders表,需要计算2022年及以后每个日期的12个月滚动去重活跃客户数。我尝试了如下SQL代码:

SELECT
  order_date,
  COUNT(DISTINCT customer_id) OVER (ORDER BY order_date RANGE INTERVAL '360' day PRECEDING) AS customers_12m
  -- 用窗口函数创建360天的时间范围,统计该时段内的去重客户数
FROM
  orders
WHERE
  order_date >= '2021-01-01'
GROUP BY
  order_date
HAVING
  order_date >= '2022-01-01'

但在不同DBMS平台(Redshift、Exasol、Trino(Presto))上遇到了不同错误(如不支持DISTINCT窗口聚合、不支持RANGE INTERVAL语法等)。请问仅用SQL能否实现该需求?

示例输入

order_datecustomer_id
2023-01-01X
2023-01-01Y
2023-01-02X
2023-01-03X
2023-01-04Z
2023-01-05Z

示例输出(以1天滚动代替360天)

order_datecustomers_1d
2023-01-012 (X 和 Y)
2023-01-022 (X 和 Y)
2023-01-031 (仅 X)
2023-01-042 (X 和 Z)
2023-01-051 (仅 Z)

解决方案:通用SQL实现

当然可以实现,以下是兼容Redshift、Exasol、Trino等多平台的通用方案,核心思路是用日期维度表+条件聚合规避窗口函数的兼容性限制:

具体SQL代码

-- 1. 生成需要统计的目标日期范围(已有日期维度表可直接替换)
WITH target_dates AS (
  SELECT generate_series(
    DATE '2022-01-01',
    (SELECT MAX(order_date) FROM orders),
    INTERVAL '1 day'
  )::DATE AS order_date
),
-- 2. 先对订单按日期+客户去重,减少后续计算量
distinct_customer_dates AS (
  SELECT DISTINCT order_date, customer_id
  FROM orders
)
-- 3. 计算每个日期的12个月滚动去重客户数
SELECT
  td.order_date,
  COUNT(DISTINCT dcd.customer_id) AS customers_12m
FROM target_dates td
LEFT JOIN distinct_customer_dates dcd
  ON dcd.order_date BETWEEN td.order_date - INTERVAL '12 months' AND td.order_date
GROUP BY td.order_date
ORDER BY td.order_date;

针对不同平台的微调

  • Redshift:generate_series需用递归CTE替代:
    WITH target_dates AS (
      SELECT DATE '2022-01-01' AS order_date
      UNION ALL
      SELECT order_date + INTERVAL '1 day'::DATE
      FROM target_dates
      WHERE order_date < (SELECT MAX(order_date) FROM orders)
    )
    
  • Trino(Presto):日期生成语法调整为:
    SELECT date_add('day', i, DATE '2022-01-01') AS order_date
    FROM unnest(sequence(0, date_diff('day', DATE '2022-01-01', (SELECT MAX(order_date) FROM orders)))) t(i)
    
  • Exasol:无需调整,直接使用通用代码即可。

方案优势

  • 完全规避了窗口函数中COUNT(DISTINCT)和RANGE INTERVAL的兼容性问题;
  • 提前去重减少了关联计算的数据量,提升性能;
  • 左连接确保无订单的日期也会被输出(若需过滤可加HAVING COUNT(DISTINCT dcd.customer_id) > 0)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 00:40:15