![](/img/trans.png)
[英]How to match elements of a BigQuery array with dates by starting from a given date?
[英]How to determine date paid given billing and payment data in BigQuery
我需要知道何时支付账单以确定支付的早晚时间。 不幸的是,我只有账单创建数据和付款记录。
--raw data
WITH bill AS (
SELECT 'b1' AS id, DATE('2022-01-01') AS created, DATE('2022-01-15') AS due, 50 AS amount UNION ALL
SELECT 'b2', DATE('2022-01-01'), DATE('2022-01-30'), 50 UNION ALL
SELECT 'b3', DATE('2022-01-03'), DATE('2022-01-17'), 50 UNION ALL
SELECT 'b4', DATE('2022-01-03'), DATE('2022-02-01'), 50 UNION ALL
SELECT 'b5', DATE('2022-01-05'), DATE('2022-01-19'), 50 UNION ALL
SELECT 'b6', DATE('2022-01-05'), DATE('2022-02-04'), 50
),
payment AS (
SELECT 'p1' AS id, DATE('2022-01-10') AS made, 50 AS amount UNION ALL
SELECT 'p2', DATE('2022-01-11'), 50
)
-- setup
SELECT * FROM bill
我想要一个查询,它返回账单表中的所有数据以及支付账单的日期,这在理论上是从支付表中派生的。
在上面的示例中,解决方案可能是按到期日对账单行进行排序并相应地应用付款:
--raw data
WITH bill AS (
SELECT 'b1' AS id, DATE('2022-01-01') AS created, DATE('2022-01-15') AS due, 50 AS amount UNION ALL
SELECT 'b2', DATE('2022-01-01'), DATE('2022-01-30'), 50 UNION ALL
SELECT 'b3', DATE('2022-01-03'), DATE('2022-01-17'), 50 UNION ALL
SELECT 'b4', DATE('2022-01-03'), DATE('2022-02-01'), 50 UNION ALL
SELECT 'b5', DATE('2022-01-05'), DATE('2022-01-19'), 50 UNION ALL
SELECT 'b6', DATE('2022-01-05'), DATE('2022-02-04'), 50
),
payment AS (
SELECT 'p1' AS id, DATE('2022-01-10') AS made, 50 AS amount UNION ALL
SELECT 'p2', DATE('2022-01-11'), 50
),
--start solution
p AS (
SELECT
payment.id,
payment.made,
payment.amount,
SUM( payment.amount ) OVER (
ORDER BY payment.made
) AS amount_cumulative
FROM payment
),
b AS (
SELECT
bill.id,
bill.created,
bill.due,
bill.amount,
SUM( bill.amount ) OVER (
ORDER BY bill.due
) AS amount_cumulative
FROM bill
),
repayments AS (
SELECT
b.*,
p.made,
ROW_NUMBER() OVER (
PARTITION BY b.id
ORDER BY p.made ASC
) AS seq
FROM b
LEFT JOIN p
ON b.amount_cumulative <= p.amount_cumulative
WHERE p.made IS NOT NULL
)
SELECT
b.*,
repayments.made AS payment_date
FROM b
LEFT JOIN repayments
ON b.id = repayments.id
WHERE (repayments.seq = 1 OR repayments.seq IS NULL)
ORDER BY b.id
但是,如果我们更改某些帐单和付款日期,该解决方案就会失效(因为付款必须应用于具有未结余额和付款时最早到期日的帐单)。 例如:
--raw data
WITH bill AS (
SELECT 'b1' AS id, DATE('2022-01-01') AS created, DATE('2022-01-15') AS due, 50 AS amount UNION ALL
SELECT 'b2', DATE('2022-01-01'), DATE('2022-01-30'), 50 UNION ALL
SELECT 'b3', DATE('2022-01-03'), DATE('2022-01-17'), 50 UNION ALL
SELECT 'b4', DATE('2022-01-03'), DATE('2022-02-01'), 50 UNION ALL
SELECT 'b5', DATE('2022-01-05'), DATE('2022-01-19'), 50 UNION ALL
SELECT 'b6', DATE('2022-01-05'), DATE('2022-02-04'), 50
),
payment AS (
SELECT 'p1' AS id, DATE('2022-01-02') AS made, 100 AS amount UNION ALL
SELECT 'p2', DATE('2022-01-11'), 50
),
--start solution
p AS (
SELECT
payment.id,
payment.made,
payment.amount,
SUM( payment.amount ) OVER (
ORDER BY payment.made
) AS amount_cumulative
FROM payment
),
b AS (
SELECT
bill.id,
bill.created,
bill.due,
bill.amount,
SUM( bill.amount ) OVER (
ORDER BY bill.due
) AS amount_cumulative
FROM bill
),
repayments AS (
SELECT
b.*,
p.made,
ROW_NUMBER() OVER (
PARTITION BY b.id
ORDER BY p.made ASC
) AS seq
FROM b
LEFT JOIN p
ON b.amount_cumulative <= p.amount_cumulative
WHERE p.made IS NOT NULL
)
SELECT
b.*,
repayments.made AS payment_date
FROM b
LEFT JOIN repayments
ON b.id = repayments.id
WHERE (repayments.seq = 1 OR repayments.seq IS NULL)
ORDER BY b.id
如果p1
的amount
= 75(在这种情况下b2
应保持未完全支付,但b3
应在2022-01-11
全额支付),则此示例更加棘手。
我可以通过查询获得payment_date
吗? 如果是这样,那看起来像什么?
请参考下面的查询。 想法是在一定范围内分配付款。
--raw data
WITH bill AS (
SELECT 'b1' AS id, DATE('2022-01-01') AS created, DATE('2022-01-15') AS due, 50 AS amount UNION ALL
SELECT 'b2', DATE('2022-01-01'), DATE('2022-01-30'), 50 UNION ALL
SELECT 'b3', DATE('2022-01-03'), DATE('2022-01-17'), 50 UNION ALL
SELECT 'b4', DATE('2022-01-03'), DATE('2022-02-01'), 50 UNION ALL
SELECT 'b5', DATE('2022-01-05'), DATE('2022-01-19'), 50 UNION ALL
SELECT 'b6', DATE('2022-01-05'), DATE('2022-02-04'), 50
),
payment AS (
SELECT 'p1' AS id, DATE('2022-01-10') AS made, 50 AS amount UNION ALL
SELECT 'p2', DATE('2022-01-11'), 50
), b as (
-- setup
SELECT
bill.id,
bill.created,
bill.due,
bill.amount,
SUM( bill.amount ) OVER (
ORDER BY bill.created, bill.due
) AS amount_cumulative_created,
SUM( bill.amount ) OVER (
ORDER BY bill.due
) as amount_cummulative_due,
row_number() over (order by bill.due) crn
FROM bill
order by created
), p as (
SELECT
p.id,
p.made,
p.amount,
case when
row_number() over (order by 0) =
max(un) over (partition by p.id) then
floor(p.amount / max(un) over (partition by p.id)) +
mod(p.amount, max(un) over (partition by p.id))
else
floor(p.amount / max(un) over (partition by p.id))
end new_amount,
row_number() over (order by 0) prn
FROM
(select *,
row_number() over (order by payment.made) prn
from payment) p join b
on p.prn = b.crn
,unnest(generate_array(1,
(select coalesce(max(b.crn),0)+1 from b
where p.amount > b.amount_cummulative_due
and p.made between b.created and b.due),
1)) un
), p_distrib as (
select *,
SUM( p.new_amount ) OVER (
ORDER BY p.prn
) AS payment_cumulative, from p
)
select b.*,
(select min(pd.made) from p_distrib pd
where
--- Adjust here for what date takes preference - created vs. due.
--- Replace amount_cumulative_created with amount_cumulative_due as needed
b.amount_cumulative_created <= pd.payment_cumulative
and pd.made between b.created and b.due)
from b;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.