将结果分配给特定客户端的给定时间窗口中最旧的记录

问题描述 投票:0回答:1

我有两个表,t1 和 t2,具有相同的列布局:client_id、transaction_date、price、product。第一个表包含主要产品,第二个表包含其他产品。我想检查是否向购买主要产品的同一客户追加销售其他产品(并检查价格)。我假设当主产品交易给同一客户之前或之后 10 天内额外销售产品时,就会发生追加销售。

t1:

client_id 交易日期 价格 产品
445 2024年3月1日 100 主要
445 2024年4月1日 100 主要
445 2024年4月2日 100 主要
339 2024年4月5日 100 主要
339 2024年4月6日 100 主要

t2:

client_id 交易日期 价格 产品
445 2024年4月5日 40 额外
339 2024年4月5日 40 额外
339 2024年4月6日 40 额外

想要:

client_id 交易日期 价格 产品 xsell_price
445 2024年3月1日 100 主要
445 2024年4月1日 100 主要 40
445 2024年4月2日 100 主要
339 2024年4月5日 100 主要 80
339 2024年4月6日 100 主要

我有两个无法解决的主要问题:

  1. 我希望附加产品仅分配给最旧或最新的匹配交易,以避免重复计算。例如,如果 client_id = 445 在 01.03.2024、01.04.2024 和 02.04.2024 购买了主要产品,然后在 05.04.2024 购买了附加产品,我希望附加产品的价格仅添加到该交易于 2024 年 4 月 1 日进行。 (不包括 2024 年 3 月 1 日,因为它已经超过 10 天)。

  2. 额外的产品可以多次购买,这会产生重复。例如,client_id = 339 在 01.04.2024、02.04.2024 购买了主产品,然后在 05.04.2024 和 06.04.2024 购买了附加产品,在这种情况下,这两个主要交易将重复。与第一点类似,我希望附加产品的总和仅添加到最旧或最新的主要交易中。

我尝试了这段代码,对于第一点似乎没问题,但它没有解决第二点的重复问题。

with tmp as (select t1.*, 
    t2.price as xsell_price, t2.transaction_date as transaction_date_xsell 
from t1 
left join t2 on t1.client_id = t2.client_id and t2.transaction_date between (t1.transaction_date - 5) and (t1.transaction_date + 5)), 
tmp2 as (select t1.*, 
    row_number() over (partition by client_id, transaction_date_xsell order by transaction_date_xsell desc) as row_num 
from tmp) 
select t1.*, 
    case when row_num = 1 then xsell_price end as xsell_price_calc 
from tmp2;
sql oracle
1个回答
0
投票

一种选择是使用 Over() 子句的 Partition By 和 Order By 部分中的 case 表达式来定义左连接表的 ROW_NUMBER。然后使用条件聚合ang group by:

WITH    --  S a m p l e    D a t a :
    t1 (CLIENT_ID,  TRANSACTION_DATE,   PRICE,  PRODUCT) AS
        ( Select 445, To_Date('01.03.2024', 'dd.mm.yyyy'), 100, 'main' From Dual Union All
          Select 445, To_Date('01.04.2024', 'dd.mm.yyyy'), 100, 'main' From Dual Union All
          Select 445, To_Date('02.04.2024', 'dd.mm.yyyy'), 100, 'main' From Dual Union All
          Select 339, To_Date('05.04.2024', 'dd.mm.yyyy'), 100, 'main' From Dual Union All
          Select 339, To_Date('06.04.2024', 'dd.mm.yyyy'), 100, 'main' From Dual 
        ), 
    t2 (CLIENT_ID,  TRANSACTION_DATE,   PRICE,  PRODUCT) AS
        ( Select 445, To_Date('05.04.2024', 'dd.mm.yyyy'), 40, 'additional' From Dual Union All
          Select 339, To_Date('05.04.2024', 'dd.mm.yyyy'), 40, 'additional' From Dual Union All
          Select 339, To_Date('06.04.2024', 'dd.mm.yyyy'), 40, 'additional' From Dual 
        )
--    M a i n    S Q L :
SELECT    CLIENT_ID,    TRANSACTION_DATE,   PRICE,  PRODUCT, 
          Sum(Case When RN = 1 Then XSELL_PRICE End) "XSELL_PRICE"
FROM    ( Select    t1.CLIENT_ID,   t1.TRANSACTION_DATE,    t1.PRICE,   t1.PRODUCT,  
                    t2.PRICE "XSELL_PRICE",
                    Row_Number() Over(Partition By Case When t2.PRICE Is Not Null Then t1.CLIENT_ID Else 0 End, t2.TRANSACTION_DATE  
                                      Order By Case When t2.PRICE Is Not Null Then t1.TRANSACTION_DATE End, t2.TRANSACTION_DATE ) "RN"
          From      t1
          Left Join t2 ON(t2.CLIENT_ID = t1.CLIENT_ID And t2.TRANSACTION_DATE - t1.TRANSACTION_DATE <= 10)
        )
GROUP BY  CLIENT_ID,    TRANSACTION_DATE,   PRICE,  PRODUCT
ORDER BY  CLIENT_ID Desc, TRANSACTION_DATE  
/*    R e s u l t :
 CLIENT_ID TRANSACTION_DATE      PRICE PROD XSELL_PRICE
---------- ---------------- ---------- ---- -----------
       445 01.03.24                100 main            
       445 01.04.24                100 main          40
       445 02.04.24                100 main            
       339 05.04.24                100 main          80
       339 06.04.24                100 main               */
© www.soinside.com 2019 - 2024. All rights reserved.