【问题标题】:SQL conditional rolling sumSQL条件滚动和
【发布时间】:2020-04-29 13:36:48
【问题描述】:

我正在使用 BigQuery 标准 SQL,需要从我的事务表中按客户 (cust_id) 提取 submit_amount 的滚动总和。

但是,我只能在滚动总和中包含某些交易。我的条件是:

  • paid_date 可能需要包含在滚动和中的行 IS NULL>= 正在计算的行的 submit_date
  • 可能需要包含在滚动总和中的行的submit_datesubmit_date 正在计算的行之前的 0 到 30 天之间
  • cust_id 必须匹配当前行 cust_id
  • 这是我的数据样本,其中包含我想要计算的 accrued_amount 字段。我还在这里添加了一个字段,只是为了更清楚地说明哪些交易应该符合每行中的滚动总和。

    txn_id | cust_id |提交日期 |支付日期 |提交金额 |应计金额 | qual_txn_id -------------------------------------------------- ----------------------------------------- 1 | 1 | 2020-01-01 | 2020-01-15 | 10 | 10 | 1 2 | 1 | 2020-01-12 | 2020-02-01 | 5 | 15 | 1, 2 3 | 1 | 2020-01-25 |空 | 2 | 7 | 2、3 4 | 1 | 2020-02-05 |空 | 4 | 6 | 3、4 5 | 1 | 2020-02-06 |空 | 1 | 7 | 3、4、5 6 | 1 | 2020-03-01 | 2020-03-15 | 3 | 8 | 4、5、6 7 | 2 | 2020-03-05 | 2020-03-20 | 6 | 6 | 7 8 | 2 | 2020-03-25 |空 | 2 | 2 | 8

    我已经制定了标准#2 和#3,但不确定如何合并#1。以下是我当前的查询:

    SELECT 
      txn_id, cust_id, submit_date, paid_date, submit_amount,
      SUM(submit_amount) OVER (
        PARTITION BY cust_id
        ORDER BY UNIX_DATE(submit_date)
        RANGE BETWEEN 29 PRECEDING AND CURRENT ROW)
      AS accrued_amount
    FROM t;
    

    我尝试使用CASE WHEN 代替submit_amount(在SUM() 内)应用paid_date 标准,但无法将正确的行相互比较。

    这样做的正确方法是什么?

    【问题讨论】:

    • submit_date is between 0 and 30 days prior to current row submit_date
    • 我的意思是,可能需要包含在滚动总和中的行的提交日期需要在计算哪一行之前的 0-30 天。

    标签: sql google-bigquery


    【解决方案1】:

    以下是 BigQuery 标准 SQL

    #standardSQL
    SELECT * EXCEPT(arr),
        (
          SELECT SUM(IF(paid_date IS NULL OR paid_date >= submit_date, submit_amount, 0))
          FROM UNNEST(arr) 
        ) AS accrued_amount, 
        (
          SELECT STRING_AGG(IF(paid_date IS NULL OR paid_date >= submit_date, CAST(txn_id AS STRING), NULL))
          FROM UNNEST(arr) 
        ) AS qual_txn_id 
    FROM (
      SELECT *,
        ARRAY_AGG(STRUCT(txn_id, paid_date, submit_amount)) OVER (
          PARTITION BY cust_id 
          ORDER BY UNIX_DATE(submit_date)
          RANGE BETWEEN 29 PRECEDING AND CURRENT ROW
        ) AS arr  
      FROM `project.dataset.table`
    )    
    

    如果应用到您的问题中的样本数据,如下例所示

    #standardSQL
    WITH `project.dataset.table` AS (
      SELECT 1 txn_id, 1 cust_id, DATE '2020-01-01' submit_date, DATE '2020-01-15' paid_date, 10 submit_amount UNION ALL
      SELECT 2, 1, '2020-01-12', '2020-02-01', 5, UNION ALL
      SELECT 3, 1, '2020-01-25', NULL, 2 UNION ALL
      SELECT 4, 1, '2020-02-05', NULL, 4 UNION ALL
      SELECT 5, 1, '2020-02-06', NULL, 1 UNION ALL
      SELECT 6, 1, '2020-03-01', '2020-03-15', 3 UNION ALL
      SELECT 7, 2, '2020-03-05', '2020-03-20', 6 UNION ALL
      SELECT 8, 2, '2020-03-25', NULL, 2
    )
    SELECT * EXCEPT(arr),
        (
          SELECT SUM(IF(paid_date IS NULL OR paid_date >= submit_date, submit_amount, 0))
          FROM UNNEST(arr) 
        ) AS accrued_amount, 
        (
          SELECT STRING_AGG(IF(paid_date IS NULL OR paid_date >= submit_date, CAST(txn_id AS STRING), NULL))
          FROM UNNEST(arr) 
        ) AS qual_txn_id 
    FROM (
      SELECT *,
        ARRAY_AGG(STRUCT(txn_id, paid_date, submit_amount)) OVER (
          PARTITION BY cust_id 
          ORDER BY UNIX_DATE(submit_date)
          RANGE BETWEEN 29 PRECEDING AND CURRENT ROW
        ) AS arr  
      FROM `project.dataset.table`
    )    
    

    结果是

    Row txn_id  cust_id submit_date paid_date   submit_amount   accrued_amount  qual_txn_id  
    1   1       1       2020-01-01  2020-01-15  10              10              1    
    2   2       1       2020-01-12  2020-02-01  5               15              1,2  
    3   3       1       2020-01-25  null        2               7               2,3  
    4   4       1       2020-02-05  null        4               6               3,4  
    5   5       1       2020-02-06  null        1               7               3,4,5    
    6   6       1       2020-03-01  2020-03-15  3               8               4,5,6    
    7   7       2       2020-03-05  2020-03-20  6               6               7    
    8   8       2       2020-03-25  null        2               2               8   
    

    此外,以下是重构的 - 上面的版本稍微不那么冗长,输出完全相同

    #standardSQL
    SELECT * EXCEPT(arr),
        (
          SELECT AS STRUCT 
            SUM(IF(qual, submit_amount, 0)) AS accrued_amount,
            STRING_AGG(IF(qual, CAST(txn_id AS STRING), NULL)) AS qual_txn_id
          FROM UNNEST(arr), UNNEST([paid_date IS NULL OR paid_date >= submit_date]) qual 
        ).* 
    FROM (
      SELECT *,
        ARRAY_AGG(STRUCT(txn_id, paid_date, submit_amount)) OVER (
          PARTITION BY cust_id 
          ORDER BY UNIX_DATE(submit_date)
          RANGE BETWEEN 29 PRECEDING AND CURRENT ROW
        ) AS arr  
      FROM `project.dataset.table`
    ) 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-08-18
      • 2017-07-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-26
      • 1970-01-01
      • 2020-08-29
      相关资源
      最近更新 更多