【问题标题】:How to solve a nested aggregate function in SQL?如何解决 SQL 中的嵌套聚合函数?
【发布时间】:2020-09-09 02:11:38
【问题描述】:

我正在尝试使用嵌套聚合函数。我知道 SQL 不支持它,但我真的需要做类似下面的查询。基本上,我想计算每天的用户数。但我只想计算在 15 天窗口内(相对于特定日期)未完成订单以及在 30 天窗口内(相对于特定日期)完成任何订单的用户。我已经知道使用常规子查询无法解决此问题(它不允许更改每个日期的子查询值)。 “id”和“state”属性与订单相关。另外,我正在使用 Fivetran 和 Snowflake。

SELECT
db.created_at::date as Date,
count(case when
  
    (count(case when (db.state = 'finished') 
        and (db.created_at::date between dateadd(day,-15,Date) and dateadd(day,-1,Date)) then db.id end)

    = 0) and 

    (count(case when (db.state = 'finished') 
        and (db.created_at::date between dateadd(day,-30,Date) and dateadd(day,-16,Date)) then db.id end)

    > 0) then db.user end)

FROM
data_base as db

WHERE
db.created_at::date between '2020-01-01' and dateadd(day,-1,current_date)

GROUP BY Date

换句话说,我想以“current_date”为每个日期更改的方式转换以下查询。

WITH completed_15_days_before AS (
  
  select
db.user as User,
count(case when db.state = 'finished' then db.id end) as Completed

  from
data_base as db

  where
db.created_at::date between dateadd(day,-15,current_date) and dateadd(day,-1,current_date)

  group by User
  ),

completed_16_days_before AS (
  
  select
db.user as User,
count(case when db.state = 'finished' then db.id end) as Completed

  from
data_base as db

  where
db.created_at::date between dateadd(day,-30,current_date) and dateadd(day,-16,current_date)
  
  group by User
  )


SELECT 
date(db.created_at) as Date, 
count(distinct case when comp_15.completadas = 0 and comp_16.completadas > 0 then comp_15.user end) as "Total Users Churn",
count(distinct case when comp_15.completadas > 0 then comp_15.user end) as "Total Users Active",
week(Date) as Week

FROM 
data_base as db
left join completadas_15_days_before as comp_15 on comp_15.user = db.user
left join completadas_16_days_before as comp_16 on comp_16.user = db.user

WHERE
db.created_at::date between '2020-01-01' and dateadd(day,-1,current_date)

GROUP BY Date

有人知道如何解决这个难题吗?非常感谢!

【问题讨论】:

  • 您已标记 3 个 RDBMS - 请仅标记感兴趣的 RDBMS。
  • 我已经删除了冲突...随时添加正确的标签。
  • "...我已经知道使用常规子查询无法解决这个问题..." -- 横向子查询正是这样做的。这取决于您的数据库。你用的是什么数据库?您还可以使用带有定制框架的窗口函数(所有标准 SQL)。但同样,您使用的是什么特定的数据库引擎?
  • @TheImpaler 我在 Snowflake 中使用 Fivetran
  • 样本数据和期望的结果确实有助于解释您想要做什么。

标签: sql postgresql snowflake-cloud-data-platform


【解决方案1】:

以下内容应大致为您提供所需的内容 - 没有样本数据很难进行测试,但应该是您足够好的起点,然后对其进行修改以提供您想要的内容。 我已经对代码进行了评论,希望能解释每个部分的作用。

-- set parameter for the first date you want to generate the resultset for
set start_date = TO_DATE('2020-01-01','YYYY-MM-DD');
-- calculate the number of days between the start_date and the current date
set num_days =  (Select datediff(day, $start_date , current_date()+1));

--generate a list of all the dates from the start date to the current date
-- i.e. every date that needs to appear in the resultset
WITH date_list as (
select
  dateadd(
    day,
    '-' || row_number() over (order by null),
    dateadd(day, '+1', current_date())
  ) as date_item
from table (generator(rowcount => ($num_days)))
)
--Create a list of all the orders that are in scope
-- i.e. 30 days before the start_date up to the current date
-- amend WHERE clause to in/exclude records as appropriate
,order_list as (
SELECT created_at, rt_id
  from data_base
  where created_at between dateadd(day,-30,$start_date) and current_date()
  and state = 'finished'
)
SELECT dl.date_item
,COUNT (DISTINCT ol30.RT_ID) AS USER_COUNT
,COUNT (ol30.RT_ID) as ORDER_COUNT
FROM date_list dl
-- get all orders between -30 and -16 days of each date in date_list
left outer join order_list ol30 on ol30.created_at between dateadd(day,-30,dl.date_item) and dateadd(day,-16,dl.date_item)
-- exclude records that have the same RT_ID as in the ol30 dataset but have a date between 0 amd -15 of the date in date_list
WHERE NOT EXISTS (SELECT ol15.RT_ID 
                  FROM order_list ol15 
                  WHERE ol30.RT_ID = ol15.RT_ID 
                  AND ol15.created_at between dateadd(day,-15,dl.date_item) and dl.date_item)
GROUP BY dl.date_item
ORDER BY dl.date_item;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-03-20
    • 2020-11-06
    • 1970-01-01
    • 2020-11-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多