在SQL查询中仅对特定列和FIFO计算进行分组

时间:2019-10-03 03:45:41

标签: mysql sql

我有以下示例数据:

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

我对从何处开始进行这项工作有点迷茫。

2 个答案:

答案 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)


可以对这两种方法进行基准测试以获得最佳性能。

相关问题