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

如何查询不同日期重复购买同一商品的客户及相关信息

问题:找出不同日期多次购买同一商品的客户及相关统计

我需要找出在不同日期多次购买同一商品的客户,现有SQL代码已实现部分功能,但无法在不添加至GROUP BY子句的情况下获取客户FIRST_NAME、LAST_NAME和PRODUCT_NAME,还需统计该商品在不同日期的购买次数。怀疑GROUP BY并非最优方案,想知道用自连接(self JOIN)或LEAD函数是否更合适?

相关表结构及当前查询代码

CREATE TABLE customers 
(CUSTOMER_ID, FIRST_NAME, LAST_NAME) AS
SELECT 1, 'Abby', 'Katz' FROM DUAL UNION ALL
SELECT 2, 'Lisa', 'Saladino' FROM DUAL UNION ALL
SELECT 3, 'Jerry', 'Torchiano' FROM DUAL;

CREATE TABLE items 
(PRODUCT_ID, PRODUCT_NAME) AS
SELECT 100, 'Black Shoes' FROM DUAL UNION ALL
SELECT 101, 'Brown Shoes' FROM DUAL UNION ALL
SELECT 102, 'White Shoes' FROM DUAL;

CREATE TABLE purchases
(CUSTOMER_ID, PRODUCT_ID, QUANTITY, PURCHASE_DATE) AS
SELECT 1, 100, 1, TIMESTAMP'2022-10-11 09:54:48' FROM DUAL UNION ALL
SELECT 1, 100, 1, TIMESTAMP '2022-10-11 19:04:18' FROM DUAL UNION ALL
SELECT 2, 101,1, TIMESTAMP '2022-10-11 09:54:48' FROM DUAL UNION ALL
SELECT 2,101,1, TIMESTAMP '2022-10-17 19:04:18' FROM DUAL UNION ALL
SELECT 3, 101,1, TIMESTAMP '2022-10-11 09:54:48' FROM DUAL UNION ALL
SELECT 3,102,1, TIMESTAMP '2022-10-17 19:04:18' FROM DUAL;

With CTE as (
 SELECT customer_id
                ,product_id 
                ,trunc(purchase_date)
  FROM purchases
  GROUP BY customer_id 
                    ,product_id
                   ,trunc(purchase_date)
)
SELECT  customer_id, product_id
FROM CTE
GROUP BY customer_id                  ,product_id 
HAVING COUNT(1)>1

解决方案

方法一:优化现有GROUP BY方案(最直观易维护)

不需要重构逻辑,只要在筛选出符合条件的客户-商品组合后,关联客户表和商品表获取名称,同时直接统计不同日期的购买次数:

WITH customer_product_dates AS (
    SELECT 
        customer_id,
        product_id,
        TRUNC(purchase_date) AS purchase_day
    FROM purchases
    GROUP BY customer_id, product_id, TRUNC(purchase_date)
), qualified_pairs AS (
    SELECT 
        customer_id,
        product_id,
        COUNT(*) AS purchase_days_count -- 统计不同日期的购买次数
    FROM customer_product_dates
    GROUP BY customer_id, product_id
    HAVING COUNT(*) > 1
)
SELECT 
    q.customer_id,
    c.first_name,
    c.last_name,
    q.product_id,
    i.product_name,
    q.purchase_days_count
FROM qualified_pairs q
JOIN customers c ON q.customer_id = c.customer_id
JOIN items i ON q.product_id = i.product_id;

逻辑说明:先按「客户-商品-日期」去重,再筛选出购买日期数>1的组合,最后通过关联表直接拿到客户和商品名称,无需在主GROUP BY中额外添加非聚合字段。


方法二:自连接实现

通过自连接匹配同一客户、同一商品但不同日期的记录,再去重得到目标组合,最后统计日期数:

WITH qualified_pairs AS (
    SELECT DISTINCT
        p1.customer_id,
        p1.product_id
    FROM purchases p1
    JOIN purchases p2 
        ON p1.customer_id = p2.customer_id
        AND p1.product_id = p2.product_id
        AND TRUNC(p1.purchase_date) != TRUNC(p2.purchase_date)
)
SELECT 
    q.customer_id,
    c.first_name,
    c.last_name,
    q.product_id,
    i.product_name,
    (SELECT COUNT(DISTINCT TRUNC(purchase_date)) 
     FROM purchases p 
     WHERE p.customer_id = q.customer_id AND p.product_id = q.product_id) AS purchase_days_count
FROM qualified_pairs q
JOIN customers c ON q.customer_id = c.customer_id
JOIN items i ON q.product_id = i.product_id;

注意点:必须加DISTINCT,否则同一客户-商品对会因多次配对产生重复结果。


方法三:LEAD窗口函数实现

用窗口函数按「客户-商品」分组、日期排序,检查下一条记录的日期是否与当前不同,标记符合条件的组合后统计:

WITH purchase_with_next_day AS (
    SELECT 
        customer_id,
        product_id,
        TRUNC(purchase_date) AS purchase_day,
        LEAD(TRUNC(purchase_date)) OVER (PARTITION BY customer_id, product_id ORDER BY purchase_date) AS next_purchase_day
    FROM purchases
), qualified_pairs AS (
    SELECT DISTINCT
        customer_id,
        product_id
    FROM purchase_with_next_day
    WHERE next_purchase_day IS NOT NULL 
        AND purchase_day != next_purchase_day
)
SELECT 
    q.customer_id,
    c.first_name,
    c.last_name,
    q.product_id,
    i.product_name,
    (SELECT COUNT(DISTINCT TRUNC(purchase_date)) 
     FROM purchases p 
     WHERE p.customer_id = q.customer_id AND p.product_id = q.product_id) AS purchase_days_count
FROM qualified_pairs q
JOIN customers c ON q.customer_id = c.customer_id
JOIN items i ON q.product_id = i.product_id;

优势:如果后续需要扩展分析(比如查看相邻购买的日期间隔),这种写法更容易调整。


方案对比

  • GROUP BY优化方案:逻辑最清晰,性能稳定,适合绝大多数场景,也是最易维护的写法。
  • 自连接:适合需要复杂关联条件的场景,但容易产生重复数据,大数据量下性能可能不如其他两种方法。
  • 窗口函数:适合序列数据分析场景,代码稍复杂,但扩展性更强。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 19:25:20