我有以下示例数据:
order_id receipt_id receipt_amount total_already_invoiced_amount
14 36 30 150
14 37 30 150
15 42 30 30
16 45 30 60
16 46 40 60
17 50 40 60
17 51 40 60
17 52 40 60
receive_amount列是该特定行收到的订单金额。 栏total_already_invoiced_amount是订单的总发票金额。
我想将此表转换为一个新表,该表仅保留在扣除总发票金额(先进先出)后仍剩余收到金额的行。 例如,如果我有3条收据行,每行40条,而我的总发票额为60,那么我可以算出第一条收据行已全部开票,第二条收据行还有20条要发票,而第三条收据行完全没有发票。我无法汇总,我必须将receive_id保留为索引,因为这些日期可以有不同的日期,并且我需要能够根据该日期进行区分。 这样的查询结果如下:
order_id receipt_id received_not_invoiced_amount
16 46 10
17 51 20
17 52 40
我知道我可以按order_id
选择分组来获得汇总的回执金额,但是它也会汇总total_already_invoiced_amount,这不是我想要的。我正在尝试以下操作,但不会执行FIFO计算。...
SELECT order_id,
receipt_id,
(total_already_invoiced_amount -
(SELECT receipt_amount FROM X GROUP BY order_id)
) total_already_invoiced_amount
FROM X
WHERE (total_already_invoiced_amount -
(SELECT receipt_amount FROM X GROUP BY order_id)) < 0
我对从何处开始进行这项工作有点迷茫。
答案 0 :(得分:1)
您需要累计金额:
select order_id, receipt_id,
least(running_ra, total_already_invoiced_amount), receipt_amount)
from (select x.*,
sum(receipt_amount) over (partition by order_id order by receipt_id) as running_ra
from x
) x
where running_ra > total_already_invoiced_amount
答案 1 :(得分:1)
在没有Windowing函数(MySQL 5.7中不可用)的情况下,一种方法是进行自联接并计算订单的所有收货的总和,直到第一个表的收货行为止。然后,我们可以使用条件语句来确定差异:
查询#1 View on DB Fiddle
SELECT t1.order_id,
t1.receipt_id,
CASE
WHEN Coalesce(Sum(t2.receipt_amount), 0) <=
t1.total_already_invoiced_amount
THEN 0
ELSE Least(Coalesce(Sum(t2.receipt_amount), 0) -
t1.total_already_invoiced_amount,
t1.receipt_amount)
end AS received_not_invoiced_amount
FROM X t1
LEFT JOIN X t2
ON t2.order_id = t1.order_id
AND t2.receipt_id <= t1.receipt_id
GROUP BY t1.order_id,
t1.receipt_id,
t1.receipt_amount,
t1.total_already_invoiced_amount
HAVING received_not_invoiced_amount > 0;
| order_id | receipt_id | received_not_invoiced_amount |
| -------- | ---------- | ---------------------------- |
| 16 | 46 | 10 |
| 17 | 51 | 20 |
| 17 | 52 | 40 |
为了获得良好的性能,您可以定义以下综合索引:(order_id, receipt_id)
。
另一种方法是使用用户定义的变量。就像循环技术一样,当我们向下移动收据时,我们将在order_id上计算滚动(累积)总和。根据总和,我们确定是否收到了超额付款。有关此技术的详细说明,您可以查看以下答案:https://stackoverflow.com/a/53465139
查询#2 View on DB Fiddle
SELECT order_id,
receipt_id,
received_not_invoiced_amount
FROM (SELECT @s := IF(@o = order_id, @s + receipt_amount, receipt_amount) AS
cum_receipt_amount,
IF(@s <= total_already_invoiced_amount, 0,
Least(@s - total_already_invoiced_amount, receipt_amount)) AS
received_not_invoiced_amount,
@o := order_id AS
order_id
,
receipt_id
FROM (SELECT *
FROM X
ORDER BY order_id,
receipt_id) t1
CROSS JOIN (SELECT @o := 0,
@s := 0) vars) t2
WHERE received_not_invoiced_amount > 0;
| order_id | receipt_id | received_not_invoiced_amount |
| -------- | ---------- | ---------------------------- |
| 16 | 46 | 10 |
| 17 | 51 | 20 |
| 17 | 52 | 40 |
为了获得良好的性能,您可以定义相同的综合索引:(order_id, receipt_id)
。
您可以对这两种方法进行基准测试以获得最佳性能。