【问题标题】:Amazon Redshift SQL Count Windows FunctionAmazon Redshift SQL 计数 Windows 函数
【发布时间】:2022-01-19 22:29:00
【问题描述】:

我希望根据他们的忠诚度等级来滚动统计客户。每层都基于 LTV(0-124.99、125-198.99、199-749.99 和 750+)。这就是我现在所拥有的,它只是为每个日期返回 0,而多年来散布着一些 1。谁能帮忙解决一下windows功能?

    SELECT TRUNC(CD.date) AS "day", tier, 
    COUNT(customer_email) OVER(PARTITION BY TRUNC(CD.date), tier ORDER BY 
    TRUNC(CD.date), tier 
    ASC ROWS UNBOUNDED PRECEDING) AS "customers"
    FROM {{ @public_fact_criquet_loyalty_master AS LM}}
    RIGHT JOIN public.dim_calendar_dates CD ON TRUNC(CD.date) = TRUNC(LM.timestamp)
    WHERE TRUNC(CD.date) BETWEEN '2011-11-09' AND CURRENT_DATE
    GROUP BY TRUNC(CD.date), tier, customer_email
    ORDER BY TRUNC(CD.date), tier ASC

【问题讨论】:

  • 一条黄金法则是避免发布images的数据,我们不能从图像中剪切和粘贴,示例数据在您的问题中应该是consumable text,理想情况下为create 和 insert 语句,或者DB<>Fiddle
  • 谢谢斯图。该数据只是表明我无法让 windows 功能实际产生正确的结果,如我的问题中所述,不提供实际数据。

标签: sql amazon-redshift


【解决方案1】:

问题已变为关于如何准备数据以进行分析的问题,因此我添加了此代码以创建可允许进一步查询的基础数据。

drop table if exists test;
create table test (dt date, customer_email varchar(64), tier varchar(32));

insert into test values
('2/3/2021', 'xxxxxxxx@yyyyyy.com', '2almost_vip'),
('3/12/2021', 'xxxxxxxx@yyyyyy.com', '4the_players_club'),
('4/27/2021', 'xxxxxxxx@yyyyyy.com', '5the_players_club'),
('8/6/2021', 'xxxxxxxx@yyyyyy.com', '6the_players_club'),
('11/22/2021', 'xxxxxxxx@yyyyyy.com', '7the_players_club'),
('12/16/2021', 'xxxxxxxx@yyyyyy.com', '8the_players_club'),
('1/3/2021', 'abc@qrs.com', '2almost_vip'),
('2/12/2021', 'abc@qrs.com', '4the_players_club'),
('3/27/2021', 'abc@qrs.com', '5the_players_club'),
('7/6/2021', 'abc@qrs.com', '6the_players_club'),
('10/22/2021', 'abc@qrs.com', '7the_players_club'),
('11/16/2021', 'abc@qrs.com', '8the_players_club');

with recursive dates(d) as (
select '2021-01-01'::date as d
union all
select d + 1 as d
from dates 
where d < '2021-12-31')  -- This CTE creates dates from 2021-01-01 to 2021-12-31)
select dt, customer_email, 
    LAG(min(tier), 1) IGNORE NULLS OVER (PARTITION BY customer_email ORDER BY dt ASC) AS tier -- Find the previous non-NULL tier - remember that group by runs before window
from (
    select dt, customer_email, tier as tier  -- combine your input data with ...
    from test
    union all
    select d as dt, customer_email, null as tier -- a list of all dates per email
    from dates 
    cross join (select DISTINCT customer_email from test)  -- combine all dates with all emails
    )
group by customer_email, dt
order by customer_email, dt;

此查询的输出(基于我输入的虚拟数据)是所有电子邮件的所有日期列表,并填写了它们的层级。我不清楚您计划执行的后续步骤,所以我将保留它这里。由于此过程产生的数据比开始时要多得多,因此效率不会很高,并且很有可能最终结果不需要所有数据。如果可以消除这种数据扩展,则处理速度应该会提高。

【讨论】:

  • 这正是我所需要的。由于数据量很大,我将把它用作定义表,然后调用它来计算每天每一层中唯一记录的计数。非常感谢!
  • 很高兴听到,一切顺利
【解决方案2】:

您已按 TRUNC(CD.date) 分区,它以我认为您不希望的方式分解计数组。你在找这个吗?

COUNT(customer_email) OVER(PARTITION BY tier ORDER BY day ASC 
    ROWS UNBOUNDED PRECEDING) AS "customers"

PS。您可以在窗口函数中使用“day”,因为它已在第一个结果列中定义为“TRUNC(CD.date)”。

【讨论】:

  • 谢谢比尔,这是非常有用的信息。这确实改善了我的结果,但仍然不是我想要的。因此,它每天增加一个,而不是实际计算该特定层级的客户。
  • 这是一些样本/测试数据和预期结果将有助于阐明您想要什么的地方。您是否正在寻找 count() 而不是滚动计数?窗口函数不会像 group by 那样减少行数。要记住的一件事是,当您在同一查询级别中混合窗口函数和分组依据时,分组依据首先运行,然后是窗口函数。如果您期望 group by 将在窗口结果中运行,您将需要第二级查询。
  • 很难给出简单的数据。我认为至少解释它可能更有意义。因此,我们拥有客户达到但达到一定 LTV 阈值的这 4 个忠诚度等级。如果他们在 21 年 1 月 20 日购买 130 美元,在 21 年 9 月 13 日再购买 85 美元,他们将在 21 年 1 月 20 日至 21 年 9 月 12 日期间获得 2almost_vip,然后从 2013 年 9 月 3 日开始获得 3vip,直到他们下次购买。我会计算每天每一层有多少人。
  • 所以这只是“选择...,计数(客户电子邮件)...按天分组,层”?我怀疑您可能需要更多,但可能是起点
  • 是的,作为起点。我有进入新等级的日期,但不是每天的日期。在上面的示例中,我只有 21 年 1 月 20 日作为 2almost_vip 级别,以及介于 21 年 9 月 21 日达到 3vip 之间的所有日子。我想要完成的是 1)在每个日期获得层级和 2)在每一天获得每个层级中每个客户的计数
猜你喜欢
  • 2014-04-28
  • 1970-01-01
  • 2021-10-07
  • 1970-01-01
  • 1970-01-01
  • 2017-07-23
  • 1970-01-01
  • 1970-01-01
  • 2019-11-16
相关资源
最近更新 更多