【问题标题】:Updating query to return most recent revenue date/value prior to previous year/quarter date/values (snowflake)更新查询以返回上一年/季度日期/值之前的最新收入日期/值(雪花)
【发布时间】:2021-12-22 11:44:11
【问题描述】:

我写了以下查询。加入 f7 和 f8 是因为有时上一季度/年度的收入为 NULL,但仅适用于那一天。如果 15 天前的收入是正数,那么我们知道它仍然是一个活动帐户,而 NULL 是由于合同暂时失效。

无论如何,我正在尝试更新这一点,以便每天获得上一季度/年度之前的最后一个实际收入值,而不是上一季度和年度之前的 15 天。我不确定这是否可行,因为每个帐户的加入日期不同。所以也许需要另一种方法。任何帮助将不胜感激。

如果我已经充分解释了这一点,请告诉我。

with
          arr_base as (select * from arr_base_table opp)
          ,cte_accounts as (select distinct account_id,
                                  account_name
                                  ,account_owner_name
                                  ,account_region_c
                                  ,account_theater_c
                                  ,owner_theater_c
                                  ,customer_first_purchase_date
                                  ,cohort_date
                                  from arr_base)
          ,cte_account_product_info as (select account_id
                                               ,account_name
                                               ,activity_date
                                               ,line_item_count
                                               ,has_casb_count
                                               ,has_casb_api_count
                                               ,has_casb_inline_count
                                               ,has_swg_count
                                               ,has_ng_swg_count
                                               ,has_swg_all_count
                                               ,has_npa_count
                                               ,has_iaas_count
                                               ,has_dlp_count
                                               ,has_dlp_adv_count
                                               ,has_dlp_std_count
                                               ,has_firewall_count
                                               ,has_cspm_count
                                               ,has_email_count
                                               ,has_rbi_count
                                               ,has_support_count
                                               ,npa_user_count
                                               ,is_casb_customer
                                               ,is_swg_customer
                                               ,is_npa_customer
                                               ,is_firewall_customer
                                               ,number_of_products
                                               ,customer_has_two_or_more_products
                                               from arr_base)
          ,cte_dates as (select distinct activity_date from arr_base)
          ,cte_arr as (select account_id
                              ,account_name
                              ,activity_date
                              ,arr
                              ,casb_api_arr
                              ,casb_inline_arr
                              ,casb_combined_arr
                              ,swg_arr
                              ,ng_swg_packages_arr
                              ,swg_combined_arr
                              ,cspm_arr
                              ,firewall_arr
                              ,iaas_storage_scan_arr
                              ,npa_arr
                              ,email_arr
                              ,rbi_arr
                              ,dlp_arr
                              ,dlp_std_arr
                              ,dlp_adv_arr
                              ,support_arr

          from arr_base)

        -- cartesian product
        select
          dim.activity_date
          ,dateadd(year,-1,dim.activity_date) as prev_year_date
          ,add_months(dim.activity_date, -3) as prev_quar_date
          ,dim.account_id
          ,dim.account_name
          ,dim.account_owner_name
          ,dim.account_region_c
          ,dim.account_theater_c
          ,dim.owner_theater_c
          ,dim.customer_first_purchase_date
          ,dim.cohort_date
          ,f4.line_item_count
          ,f5.line_item_count as line_item_count_prev_year
          ,f6.line_item_count as line_item_count_prev_quarter
          ,f1.arr as arr_current_year
          ,f2.arr as arr_prev_year
          ,f3.arr as arr_prev_quarter
          ,f7.arr as arr_prev_year_plus15
          ,f8.arr as arr_prev_quarter_plus15
        from
        (
         select
          a.*
          ,d.activity_date
         from cte_accounts a cross join cte_dates d
        ) as dim
              left outer join cte_arr f1 on dim.account_id = f1.account_id and dim.activity_date = f1.activity_date
              left outer join cte_arr f2 on dim.account_id = f2.account_id and (dateadd(year,-1,dim.activity_date) = f2.activity_date)
              left outer join cte_arr f3 on dim.account_id = f3.account_id and (add_months(dim.activity_date, -3) = f3.activity_date)
              left outer join cte_account_product_info f4 on dim.account_id = f4.account_id and dim.activity_date = f4.activity_date
              left outer join cte_account_product_info f5 on dim.account_id = f5.account_id and (dateadd(year,-1,dim.activity_date) = f5.activity_date)
              left outer join cte_account_product_info f6 on dim.account_id = f6.account_id and (add_months(dim.activity_date, -3) = f6.activity_date)
              left outer join cte_arr f7 on dim.account_id = f7.account_id and (dateadd(day,15,(dateadd(year,-1,dim.activity_date))) = f7.activity_date)
              left outer join cte_arr f8 on dim.account_id = f8.account_id and (dateadd(day,15,(add_months(dim.activity_date, -3))) = f8.activity_date)
        order by
          dim.activity_date
          ,dim.account_id

添加当前结果和所需结果。仅包括样本数据中的相关列。对于账户 2,arr_prev_year 为 NULL,因为该账户在 2020 年 1 月没有收到任何收入。 arr_prev_year_plus15 也是 NULL,因为整个 1 月份都没有收到任何收入。

在预期结果中,在 2020 年 1 月 31 日之前,账户 2 最近收到的收入是在 2019 年 12 月 31 日。因此,在该日期,相应的收入会在 prev_year_most_recent_date 和 arr_prev_year_most_recent 列中返回。

当前结果

Activity_date Prev_year_date Prev_quar_date prev_year_plus15_date prev_quar_plus15_date account_id arr_current_year arr_prev_year arr_prev_quarter arr_prev_year_plus15 arr_prev_quarter_plus15
Jan. 31, 2021 Jan. 31, 2020 Oct. 31, 2020 Jan. 16, 2020 Oct. 16, 2020 1 100 90 95 90 95
Jan. 31, 2021 Jan. 31, 2020 Oct. 31, 2020 Jan. 16, 2020 Oct. 16, 2020 2 100 NULL 80 NULL 80

期望的结果:

Activity_date Prev_year_date Prev_quar_date prev_year_most_recent_active_date prev_quarter_most_recent_active_date account_id arr_current_year arr_prev_year arr_prev_quarter arr_prev_year_most_recent arr_prev_quarter_most_recent
Jan. 31, 2021 Jan. 31, 2020 Oct. 31, 2020 Jan. 30, 2020 Oct. 30, 2020 1 100 90 95 90 95
Jan. 31, 2021 Jan. 31, 2020 Oct. 31, 2020 Dec. 31, 2019 Oct. 30, 2020 2 100 NULL 80 75 80

【问题讨论】:

  • 嗨迈克尔,在这种情况下,示例数据和预期结果将为您提供更好的答案。仅通过不执行此操作的查询很难说出您需要什么。如果您需要归结为获取给定属性的先前非空值,则可以在子查询中创建空指示符。然后对您的 account_id、null_indicator 进行 LAG() 分区。不过,这只是在黑暗中拍摄,因为我不完全确定您要实现的目标。
  • 很公平。让我更新示例数据和所需结果
  • 另外,请尝试提供一个最小的、可重现的示例。我猜该 SQL 的很大一部分与您的问题无关,例如您列出的大部分列
  • 是的,你是对的。将来,我将确保尽可能简化我的示例,同时仍能理解要点。感谢您的反馈。

标签: sql snowflake-cloud-data-platform


【解决方案1】:

所以我首先将你当前的 SQL 重写如下。

重点是选择你想要的列并避免*,不要在joins/where子句中使用函数。

with arr_base as (
    select 
        account_id
        ,account_name
        ,account_owner_name
        ,account_region_c
        ,account_theater_c
        ,owner_theater_c
        ,customer_first_purchase_date
        ,cohort_date
        
        ,activity_date
        ,line_item_count
        ,has_casb_count
        ,has_casb_api_count
        ,has_casb_inline_count
        ,has_swg_count
        ,has_ng_swg_count
        ,has_swg_all_count
        ,has_npa_count
        ,has_iaas_count
        ,has_dlp_count
        ,has_dlp_adv_count
        ,has_dlp_std_count
        ,has_firewall_count
        ,has_cspm_count
        ,has_email_count
        ,has_rbi_count
        ,has_support_count
        ,npa_user_count
        ,is_casb_customer
        ,is_swg_customer
        ,is_npa_customer
        ,is_firewall_customer
        ,number_of_products
        ,customer_has_two_or_more_products
        
        ,arr
        ,casb_api_arr
        ,casb_inline_arr
        ,casb_combined_arr
        ,swg_arr
        ,ng_swg_packages_arr
        ,swg_combined_arr
        ,cspm_arr
        ,firewall_arr
        ,iaas_storage_scan_arr
        ,npa_arr
        ,email_arr
        ,rbi_arr
        ,dlp_arr
        ,dlp_std_arr
        ,dlp_adv_arr
        ,support_arr
        
    from arr_base_table
), cte_accounts as (
    select distinct 
        account_id
        ,account_name
        ,account_owner_name
        ,account_region_c
        ,account_theater_c
        ,owner_theater_c
        ,customer_first_purchase_date
        ,cohort_date
    from arr_base
), cte_account_product_info as (
    select 
        account_id
        ,account_name
        ,activity_date
        ,line_item_count
        ,has_casb_count
        ,has_casb_api_count
        ,has_casb_inline_count
        ,has_swg_count
        ,has_ng_swg_count
        ,has_swg_all_count
        ,has_npa_count
        ,has_iaas_count
        ,has_dlp_count
        ,has_dlp_adv_count
        ,has_dlp_std_count
        ,has_firewall_count
        ,has_cspm_count
        ,has_email_count
        ,has_rbi_count
        ,has_support_count
        ,npa_user_count
        ,is_casb_customer
        ,is_swg_customer
        ,is_npa_customer
        ,is_firewall_customer
        ,number_of_products
        ,customer_has_two_or_more_products
    from arr_base
), cte_dates as (
    select distinct 
        activity_date
    from arr_base
), cte_arr as (
    select 
        account_id
        ,account_name
        ,activity_date
        ,arr
        ,casb_api_arr
        ,casb_inline_arr
        ,casb_combined_arr
        ,swg_arr
        ,ng_swg_packages_arr
        ,swg_combined_arr
        ,cspm_arr
        ,firewall_arr
        ,iaas_storage_scan_arr
        ,npa_arr
        ,email_arr
        ,rbi_arr
        ,dlp_arr
        ,dlp_std_arr
        ,dlp_adv_arr
        ,support_arr
    from arr_base
), dim_data AS (
    select
        a.account_id
        ,a.account_name
        ,a.account_owner_name
        ,a.account_region_c
        ,a.account_theater_c
        ,a.owner_theater_c
        ,a.customer_first_purchase_date
        ,a.cohort_date
        ,d.activity_date
        ,dateadd(year, -1, d.activity_date) as prev_year_date
        ,dateadd(month, -3, d.activity_date) as prev_quar_date
        ,dateadd(day, 15, prev_year_date) as prev_year_plus15d_date
        ,dateadd(day, 15, prev_quar_date) as prev_quar_plus15d_date
    from cte_accounts a 
    cross join cte_dates d
)
select
  dim.activity_date
  ,dim.prev_year_date
  ,dim.prev_quar_date
  ,dim.account_id
  ,dim.account_name
  ,dim.account_owner_name
  ,dim.account_region_c
  ,dim.account_theater_c
  ,dim.owner_theater_c
  ,dim.customer_first_purchase_date
  ,dim.cohort_date
  ,f4.line_item_count
  ,f5.line_item_count as line_item_count_prev_year
  ,f6.line_item_count as line_item_count_prev_quarter
  ,f1.arr as arr_current_year
  ,f2.arr as arr_prev_year
  ,f3.arr as arr_prev_quarter
  ,f7.arr as arr_prev_year_plus15
  ,f8.arr as arr_prev_quarter_plus15
from dim_data as dim
left outer join cte_arr f1 
    on dim.account_id = f1.account_id and dim.activity_date = f1.activity_date
left outer join cte_arr f2 
    on dim.account_id = f2.account_id and dim.prev_year_date = f2.activity_date
left outer join cte_arr f3 
    on dim.account_id = f3.account_id and dim.prev_quar_date = f3.activity_date
left outer join cte_account_product_info f4 
    on dim.account_id = f4.account_id and dim.activity_date = f4.activity_date
left outer join cte_account_product_info f5 
    on dim.account_id = f5.account_id and dim.prev_year_date = f5.activity_date
left outer join cte_account_product_info f6 
    on dim.account_id = f6.account_id and dim.prev_quar_date = f6.activity_date
left outer join cte_arr f7 
    on dim.account_id = f7.account_id and dim.prev_year_plus15d_date = f7.activity_date
left outer join cte_arr f8 
    on dim.account_id = f8.account_id and dim.prev_quar_plus15d_date = f8.activity_date
order by dim.activity_date, dim.account_id

将所有列拉入选择后,可以删除未使用的列

with arr_base as (
    select 
        account_id
        ,account_name
        ,account_owner_name
        ,account_region_c
        ,account_theater_c
        ,owner_theater_c
        ,customer_first_purchase_date
        ,cohort_date
        
        ,activity_date
        ,line_item_count
        
        ,arr

    from arr_base_table
), cte_accounts as (
    select distinct 
        account_id
        ,account_name
        ,account_owner_name
        ,account_region_c
        ,account_theater_c
        ,owner_theater_c
        ,customer_first_purchase_date
        ,cohort_date
    from arr_base
), cte_account_product_info as (
    select 
        account_id
        ,activity_date
        ,line_item_count
    from arr_base
), cte_dates as (
    select distinct 
        activity_date
    from arr_base
), cte_arr as (
    select 
        account_id
        ,activity_date
        ,arr
    from arr_base
), dim_data AS (
    select
        a.account_id
        ,a.account_name
        ,a.account_owner_name
        ,a.account_region_c
        ,a.account_theater_c
        ,a.owner_theater_c
        ,a.customer_first_purchase_date
        ,a.cohort_date
        ,d.activity_date
        ,dateadd(year, -1, d.activity_date) as prev_year_date
        ,dateadd(month, -3, d.activity_date) as prev_quar_date
        ,dateadd(day, 15, prev_year_date) as prev_year_plus15d_date
        ,dateadd(day, 15, prev_quar_date) as prev_quar_plus15d_date
    from cte_accounts a 
    cross join cte_dates d
)
select
  dim.activity_date
  ,dim.prev_year_date
  ,dim.prev_quar_date
  ,dim.account_id
  ,dim.account_name
  ,dim.account_owner_name
  ,dim.account_region_c
  ,dim.account_theater_c
  ,dim.owner_theater_c
  ,dim.customer_first_purchase_date
  ,dim.cohort_date
  ,f4.line_item_count
  ,f5.line_item_count as line_item_count_prev_year
  ,f6.line_item_count as line_item_count_prev_quarter
  ,f1.arr as arr_current_year
  ,f2.arr as arr_prev_year
  ,f3.arr as arr_prev_quarter
  ,f7.arr as arr_prev_year_plus15
  ,f8.arr as arr_prev_quarter_plus15
from dim_data as dim
left outer join cte_arr f1 
    on dim.account_id = f1.account_id and dim.activity_date = f1.activity_date
left outer join cte_arr f2 
    on dim.account_id = f2.account_id and dim.prev_year_date = f2.activity_date
left outer join cte_arr f3 
    on dim.account_id = f3.account_id and dim.prev_quar_date = f3.activity_date
left outer join cte_account_product_info f4 
    on dim.account_id = f4.account_id and dim.activity_date = f4.activity_date
left outer join cte_account_product_info f5 
    on dim.account_id = f5.account_id and dim.prev_year_date = f5.activity_date
left outer join cte_account_product_info f6 
    on dim.account_id = f6.account_id and dim.prev_quar_date = f6.activity_date
left outer join cte_arr f7 
    on dim.account_id = f7.account_id and dim.prev_year_plus15d_date = f7.activity_date
left outer join cte_arr f8 
    on dim.account_id = f8.account_id and dim.prev_quar_plus15d_date = f8.activity_date
order by dim.activity_date, dim.account_id

但你真正追求的似乎是:

with arr_base as (
    select 
        account_id
        ,account_name
        ,account_owner_name
        ,account_region_c
        ,account_theater_c
        ,owner_theater_c
        ,customer_first_purchase_date
        ,cohort_date
        
        ,activity_date
        ,line_item_count
        
        ,arr

    from arr_base_table
), cte_accounts as (
    select distinct 
        account_id
        ,account_name
        ,account_owner_name
        ,account_region_c
        ,account_theater_c
        ,owner_theater_c
        ,customer_first_purchase_date
        ,cohort_date
    from arr_base
), cte_account_product_info as (
    select 
        account_id
        ,activity_date
        ,line_item_count
    from arr_base
), cte_dates as (
    select distinct 
        activity_date
    from arr_base
), cte_arr as (
    select 
        account_id
        ,activity_date
        ,arr
    from arr_base
), cte_make_sure_only_one_arr_per_day AS (
    select 
        account_id
        ,activity_date
        ,dateadd(year, -1, activity_date) as prior_year_date
        ,dateadd(month, -3, activity_date) as prior_quater_date 
        ,max(arr) as arr
    from cte_arr
    group by 1,2
), cte_prior_year_arrs AS (
    SELECT 
        a.account_id
        a.activity_date
        b.activity_date as prior_year_activity_date
        b.arr as prior_year_arr
    FROM cte_make_sure_only_one_arr_per_day AS a
    JOIN cte_make_sure_only_one_arr_per_day AS b 
        ON a.account_id = b.account_id AND b.activity_date < a.prior_year_date
    QUALIFY ROW_NUMBER() OVER (PARTITION BY a.account_id, a.activity_date ORDER BY b.activity_date DESC) = 1
), cte_prior_quarter_arrs AS (
    SELECT 
        a.account_id
        a.activity_date
        b.activity_date as prior_quarter_activity_date
        b.arr as prior_quarter_arr
    FROM cte_make_sure_only_one_arr_per_day AS a
    JOIN cte_make_sure_only_one_arr_per_day AS b 
        ON a.account_id = b.account_id AND b.activity_date < a.prior_quater_date
    QUALIFY ROW_NUMBER() OVER (PARTITION BY a.account_id, a.activity_date ORDER BY b.activity_date DESC) = 1
), dim_data AS (
    select
        a.account_id
        ,a.account_name
        ,a.account_owner_name
        ,a.account_region_c
        ,a.account_theater_c
        ,a.owner_theater_c
        ,a.customer_first_purchase_date
        ,a.cohort_date
        ,d.activity_date
        ,dateadd(year, -1, d.activity_date) as prev_year_date
        ,dateadd(month, -3, d.activity_date) as prev_quar_date
    from cte_accounts a 
    cross join cte_dates d
)
select
  dim.activity_date
  ,f7.prior_year_activity_date as prev_year_date
  ,f8.prior_quarter_activity_date as prev_quar_date
  ,dim.account_id
  ,dim.account_name
  ,dim.account_owner_name
  ,dim.account_region_c
  ,dim.account_theater_c
  ,dim.owner_theater_c
  ,dim.customer_first_purchase_date
  ,dim.cohort_date
  ,f4.line_item_count
  ,f5.line_item_count as line_item_count_prev_year
  ,f6.line_item_count as line_item_count_prev_quarter
  ,f1.arr as arr_current_year
  ,f2.arr as arr_prev_year
  ,f3.arr as arr_prev_quarter
  ,f7.prior_year_arr as arr_prev_year_plus15
  ,f8.prior_quarter_arr as arr_prev_quarter_plus15
from dim_data as dim
left outer join cte_arr f1 
    on dim.account_id = f1.account_id and dim.activity_date = f1.activity_date
left outer join cte_arr f2 
    on dim.account_id = f2.account_id and dim.prev_year_date = f2.activity_date
left outer join cte_arr f3 
    on dim.account_id = f3.account_id and dim.prev_quar_date = f3.activity_date
left outer join cte_account_product_info f4 
    on dim.account_id = f4.account_id and dim.activity_date = f4.activity_date
left outer join cte_account_product_info f5 
    on dim.account_id = f5.account_id and dim.prev_year_date = f5.activity_date
left outer join cte_account_product_info f6 
    on dim.account_id = f6.account_id and dim.prev_quar_date = f6.activity_date
left outer join cte_prior_year_arrs f7 
    on dim.account_id = f7.account_id and dim.activity_date = f7.activity_date
left outer join cte_prior_quarter_arrs f8 
    on dim.account_id = f8.account_id and dim.activity_date = f8.activity_date
order by dim.activity_date, dim.account_id

对于当前有活动的每一天,这将有一个“前”天。但是您是想要-1 年的前一天还是-1 季度的前一天没有日期,那么cte_make_sure_only_one_arr_per_day 将需要替换为dim_data

但我认为这显示了获取所需数据的方法。

【讨论】:

  • 感谢您的建议!我将不得不花一些时间来消化并测试它。感谢您的帮助!
  • 不幸的是,看起来这并没有返回预期的结果。我想我可能需要重新发布这个问题的更简化版本,以便更好地传达我想要完成的目标
猜你喜欢
  • 2020-11-13
  • 1970-01-01
  • 1970-01-01
  • 2016-10-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-07-21
  • 1970-01-01
相关资源
最近更新 更多