SQL условная скользящая сумма - PullRequest
0 голосов
/ 29 апреля 2020

Я использую BigQuery Standard SQL и мне нужно взять скользящую сумму submit_amount по клиенту (cust_id) из моей таблицы транзакций.

Однако я могу включить только определенные транзакции в скользящая сумма Мои условия:

paid_date строки, которая может потребоваться включить в скользящую сумму IS NULL или >= submit_date строки, которая рассчитывается submit_date строки, которая может потребоваться включить в скользящую сумму, составляет от 0 до 30 дней до submit_date вычисляемая строка cust_id должна соответствовать текущей строке cust_id

Вот пример моих данных с полем accrued_amount, которое я хотел бы вычислить. Я также добавил здесь поле, чтобы прояснить, какие транзакции должны соответствовать скользящей сумме в каждой строке.

txn_id | cust_id | submit_date | paid_date  | submit_amount | accrued_amount | 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 |       NULL |             2 |             7  |   2, 3
     4 |       1 |  2020-02-05 |       NULL |             4 |             6  |   3, 4
     5 |       1 |  2020-02-06 |       NULL |             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 |       NULL |             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, но не смог его сравнить правильные ряды друг к другу.

Как правильно это сделать?

1 Ответ

2 голосов
/ 29 апреля 2020

Ниже для BigQuery Standard 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`
) 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...