【问题标题】:Conditional Window Functions条件窗函数
【发布时间】:2020-07-22 16:05:22
【问题描述】:

我有一个如下所示的销售表:

store_id    cust_id   txn_id   txn_date   amt       industry
200         1         1        20180101   21.01     1000   
200         2         2        20200102   20.01     1000
200         2         3        20200103   19        1000
200         3         4        20180103   19        1000
200         4         5        20200103   21.01     1000
300         2         6        20200104   1.39      2000
300         1         7        20200105   12.24     2000
300         1         8        20200105   25.02     2000
400         2         9        20180106   103.1     1000
400         2         10       20200107   21.3      1000

这是生成此示例表的代码:

CREATE TABLE sales(
    store_id INT,
    cust_id INT,
    txn_id INT,
    txn_date bigint,
    amt float,
    industry INT);

INSERT INTO sales VALUES(200,1,1,20180101,21.01,1000);
INSERT INTO sales VALUES(200,2,2,20200102,20.01,1000);
INSERT INTO sales VALUES(200,2,3,20200103,19.00,1000);
INSERT INTO sales VALUES(200,3,4,20180103,19.00,1000);
INSERT INTO sales VALUES(200,4,5,20200103,21.01,1000);
INSERT INTO sales VALUES(300,2,6,20200104,1.39,2000);
INSERT INTO sales VALUES(300,1,7,20200105,12.24,2000);
INSERT INTO sales VALUES(300,1,8,20200105,25.02,2000);
INSERT INTO sales VALUES(400,2,9,20180106,103.1,1000);
INSERT INTO sales VALUES(400,2,10,20200107,21.3,1000);

我想做的是创建一个新表 results 来回答以下问题:自 2020 年 1 月 3 日以来,我的 VIP 客户中有多少百分比只在我的商店购物 i); ii) 在我的商店和同行业的其他商店; iii) 仅在同行业的其他商店?将 VIP 客户定义为自 2019 年以来至少在指定商店购物过一次的人。

这是目标输出表:

store    industry   pct_my_store_only   pct_both   pct_other_stores_only
200      1000         0.5               0.5         0.0
300      2000         0.5               0.5         0.0
400      1000         0.0               1.0         0.0

我正在尝试使用窗口函数来完成此操作。到目前为止,这是我所拥有的:

CREATE TABLE results as
    SELECT s.store_id, s.industry,
    COUNT(DISTINCT (CASE WHEN s.txn_date>=20200103 THEN s.cust_id END)) * 1.0 / sum(count(DISTINCT (CASE WHEN s.txn_date>=20200103 THEN s.cust_id END))) OVER (PARTITION BY s.industry) AS pct_my_store_only
    ...AS pct_both
    ...AS pct_other_stores_only
    FROM sales s
    WHERE sales.txn_date>=20190101 
    GROUP BY s.store_id, s.industry;

以上似乎不正确;我该如何纠正这个问题?

【问题讨论】:

  • 请向我们展示您的样本数据所需的结果(您有 3 个空列)
  • @GMB:谢谢,我已经完成了目标表并添加了一个只在商店 200 购物的新客户(客户 4)。
  • @Caerus 当你说,你的商店?你指的是哪一个?
  • @JagaSrik:我的意思是每家商店都有一组自 2019 年以来在该商店购物的 VIP 客户。在这些客户中,谁只在该商店购物?例如,商店 200 有 2 个 VIP 客户(客户 2、4)。其中,只有客户 4 自 2020 年 1 月 3 日起仅在 200 家商店购物。另一位也在同行业(行业 1000)的其他商店购物。
  • VIP客户的定义是什么?

标签: mysql sql


【解决方案1】:

将每个客户的不同 store_ids 和行业连接到连接的不同 store_ids 和行业,然后使用窗口函数 avg() 和函数 find_in_set() 来确定客户是否有多少客户从每个商店购物:

with 
  stores as (
    select distinct store_id, industry
    from sales
    where txn_date >= 20190103
  ),
  customers as (
    select cust_id, 
           group_concat(distinct store_id) stores,
           group_concat(distinct industry) industries 
    from sales
    where txn_date >= 20190103
    group by cust_id
 ),
  cte as (
  select *,
    avg(concat(s.store_id) = concat(c.stores)) over (partition by s.store_id, s.industry) pct_my_store_only,
    avg(find_in_set(s.store_id, c.stores) = 0) over (partition by s.industry) pct_other_stores_only
    from stores s inner join customers c 
    on find_in_set(s.industry, c.industries) and find_in_set(s.store_id, c.stores)
  )  
select distinct store_id, industry, 
       pct_my_store_only,
       1 - pct_my_store_only - pct_other_stores_only pct_both,   
       pct_other_stores_only
from cte       
order by store_id, industry

请参阅demo
结果:

> store_id | industry | pct_my_store_only | pct_both | pct_other_stores_only
> -------: | -------: | ----------------: | -------: | --------------------:
>      200 |     1000 |            0.5000 |   0.5000 |                0.0000
>      300 |     2000 |            0.5000 |   0.5000 |                0.0000
>      400 |     1000 |            0.0000 |   1.0000 |                0.0000

【讨论】:

  • 谢谢,这看起来很棒。这是否解释了我们正在寻找自 20200103 年以来购物的 VIP 百分比的限制?
  • 在您的代码中有txn_date>=20190101,我复制了它。我现在为txn_date>=20190103编辑
  • 对,对不起,这是一个复杂的问题,我的措辞可能不清楚。 VIP 是自 20190101 以来至少在我的商店购物过一次的人。对于每家商店,我们正在寻找 i) 仅我的商店,ii) 我的商店和同行业的其他商店购物的 VIP 百分比我; iii) 自 20200103 以来只有其他商店。这非常接近——我认为我们只需要一个额外的日期过滤器,也许在 cte 中?
  • 过滤器 txn_date >= 20190103 存在于前 2 个 CTE 中。
  • 对,前两个 CTE 中的 2019 年 1 月过滤器是获取 VIP。如果我们正在寻找自 2020 年 1 月以来的购买,大概我们需要另一个过滤器,不是吗?
猜你喜欢
  • 1970-01-01
  • 2019-01-09
  • 2022-01-12
  • 2016-02-11
  • 1970-01-01
  • 2018-01-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多