【问题标题】:Find customer buying a product after purchasing another在购买另一个产品后找到购买另一个产品的客户
【发布时间】:2020-02-10 23:48:32
【问题描述】:

我有一个业务逻辑问题,我不知道如何正确制定 sql 语句来检索它。我将简化业务模型以便于讨论。 我有一张表格,记录了哪些客户在哪一天购买了什么产品。

需要找出购买产品A后购买产品B的客户的实例。我提出了以下查询:

select t."Customer",t."Date" "Date2", t."Product" "Product2",a.*
from
(
select "Customer","Date", "Product"
from test2 where "Product"='A'
) a,
test2 t
where a."Customer"= t."Customer" and t."Product"='B' and t."Date">=a."Date"

这不太对,因为它过度计算了实例,因为如果我们查看表格,客户 1 在两次购买 A 后又购买了 B,但我的查询计数了 3 次

我圈出的实例不应该被计算在内。 有没有办法来解决这个问题? 为方便起见,我附上了创建表 TEST2 的脚本。

  CREATE TABLE  "TEST2" 
   (    "Customer" VARCHAR2(26 BYTE), 
    "Date" DATE, 
    "Product" VARCHAR2(26 BYTE)
   );

Insert into  TEST2 ("Customer","Date","Product") values ('1',to_date('07-AUG-18','DD-MON-RR'),'A');
Insert into  TEST2 ("Customer","Date","Product") values ('1',to_date('07-AUG-18','DD-MON-RR'),'B');
Insert into  TEST2 ("Customer","Date","Product") values ('1',to_date('17-AUG-18','DD-MON-RR'),'A');
Insert into  TEST2 ("Customer","Date","Product") values ('1',to_date('27-SEP-18','DD-MON-RR'),'B');
Insert into  TEST2 ("Customer","Date","Product") values ('2',to_date('26-SEP-18','DD-MON-RR'),'A');
Insert into  TEST2 ("Customer","Date","Product") values ('3',to_date('01-OCT-18','DD-MON-RR'),'C');

【问题讨论】:

    标签: sql oracle


    【解决方案1】:

    假设您使用的是 12c 或更高版本,您可以使用 pattern matching (match_recognize) 执行此操作:

    CREATE TABLE TEST2 (    
      customer      VARCHAR2(26 BYTE), 
      purchase_date DATE, 
      Product       VARCHAR2(26 BYTE)
    );
    
    Insert into TEST2 (customer,purchase_date,product) values ('1',to_date('07-AUG-18','DD-MON-RR'),'A');
    Insert into TEST2 (customer,purchase_date,product) values ('1',to_date('07-AUG-18','DD-MON-RR'),'B');
    Insert into TEST2 (customer,purchase_date,product) values ('1',to_date('17-AUG-18','DD-MON-RR'),'A');
    Insert into TEST2 (customer,purchase_date,product) values ('1',to_date('27-SEP-18','DD-MON-RR'),'B');
    Insert into TEST2 (customer,purchase_date,product) values ('2',to_date('26-SEP-18','DD-MON-RR'),'A');
    Insert into TEST2 (customer,purchase_date,product) values ('3',to_date('01-OCT-18','DD-MON-RR'),'C');
    commit;
    
    select * from test2
    match_recognize (
      partition by customer
      order by purchase_date, product
      measures
        proda.purchase_date prod_a_date,
        prodb.purchase_date prod_b_date
      pattern ( proda prodb )
      define
        proda as product = 'A',
        prodb as product = 'B'
    );
    
    CUSTOMER    PROD_A_DATE             PROD_B_DATE            
    1           07-AUG-2018 00:00:00    07-AUG-2018 00:00:00    
    1           17-AUG-2018 00:00:00    27-SEP-2018 00:00:00   
    

    这说:

    • 针对每位客户 (partition by customer)
    • 按购买日期和产品排序 (order by purchase_date, product)
    • 查找产品 A 的实例,然后是产品 B (pattern ( proda prodb ))
    • define 部分说明产品是什么

    模式是一个正则表达式。您可以重新定义变量以搜索您想要的任何产品(或使产品值绑定变量 - proda as product = :bindvar)。

    如果您需要在 A 之后查找 B 的实例以及中间的其他产品购买,您可以使用排除语法 ( {-var-} ):

    insert into TEST2 (customer,purchase_date,product) 
      values ('1',to_date('20-SEP-18','DD-MON-RR'),'C');
    
    select * from test2
    match_recognize (
      partition by customer
      order by purchase_date, product
      measures
        proda.purchase_date prod_a_date,
        prodb.purchase_date prod_b_date
      pattern ( proda {-otherprod*-} prodb )
      define
        proda as product = 'A',
        prodb as product = 'B',
        otherprod as product not in ( 'A', 'B' )
    );
    
    CUSTOMER    PROD_A_DATE             PROD_B_DATE            
    1           07-AUG-2018 00:00:00    07-AUG-2018 00:00:00    
    1           17-AUG-2018 00:00:00    27-SEP-2018 00:00:00  
    

    【讨论】:

    • 太棒了,@chris!!!这正是我试图找到的解决方案,但不够聪明,无法看到它。非常感谢!!!!
    • 模式匹配真的很强大,我对它很陌生。我想快速跟进,因为我已经简化了我的问题以形成问题。如果我的模型不仅包含 3 个字段,而且还有产品描述,我是否需要将结果再链接到产品表,或者我可以将其包含在结果中吗?
    • measures 子句定义了输出列,所以将它添加到那里。或者,如果您更改为 all rows per match,它会显示组中的所有行和所有输入列
    • 是的,我想出使用措施...花了我一点时间才弄清楚,但这一切都很好...您建议的解决方案正是我需要的。像魅力一样工作!再次感谢!
    【解决方案2】:

    您可以使用聚合和having 子句:

    select customer
    from test2
    group by customer
    having min(case when product = 'A' then date end) < max(case when product = 'B' then date end);
    

    如果您想要日期,只需将having 中的函数添加到select

    【讨论】:

    • 感谢您的提示。但是,仅列出客户不是问题。我的 sql 也可以。当用户看到产品和日期时,问题就出现了。在我的简化模型中,我只将 A 列为唯一的产品,实际上,它是 A、C、F 等产品的子集......所以,用户想知道触发购买 B 的具体产品是什么做进一步分析
    猜你喜欢
    • 2013-09-05
    • 2022-10-17
    • 1970-01-01
    • 2021-03-17
    • 1970-01-01
    • 1970-01-01
    • 2019-09-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多