mysql 在特定时间段内为每个客户运行总计

wydwbb8l  于 2023-05-21  发布在  Mysql
关注(0)|答案(2)|浏览(111)

我有两张table
客户服务
| 客户|客户名称|
| --------------|--------------|
| 1|海德利·昆西|
| 2|安迪·史密斯|
| 3|莎拉·Json|
| 四|欧内斯特·福雷斯特|
付款方式
| 支付ID|日期|客户|总付款|
| --------------|--------------|--------------|--------------|
| 1| 2010-01-02 2010-01-02| 2|两百|
| 2| 2011-06-06-06-06-06-06| 3|五百|
| 3| 2020-01-01 2020-01-01| 1|七百|
| 四|2020-02-01 2020 -02-01| 1|一百|
| 5| 2020-03-10 2020-03-10| 2|四百|
| 六|2020-04-08 2020-04-08| 3|五百|
| 七|2020-07-14 2020-07-14|四|八百|
| 八|2020-09-05 2020-09-05| 1|一千|
我需要编写一个查询,返回2020年的所有月份,客户名称和每个客户的运行总数。如果买方在某个月没有付款,则显示“付款不存在”。
我想我需要使用CASE,但我不知道如何实现查询,以及如何实现运行总数,并显示2020年的月份。
我的尝试:

SELECT customer_name, SUM(sum_payment)
FROM Customers  INNER JOIN 
Payments ON Customers.customer=Payments.customer
GROUP BY customer_name;
sr4lhrrt

sr4lhrrt1#

您需要在2020年的每个月返回每个客户的记录,因此您需要

  • 所有潜在月(1-12)与所有客户之间的CROSS JOIN
  • a LEFT JOIN所有这些对与您的付款表
  • 运行总和,您可以使用SUM窗口函数

您可以通过对月份进行11 UNION ALL操作来生成月份,或者使用递归查询,从月份1开始,每次迭代添加一个月,在12停止(我个人认为后者更优雅)。

WITH RECURSIVE months AS (
    SELECT 1 AS month
    UNION ALL
    SELECT month + 1 FROM months WHERE month < 12
)
SELECT c.customer_name,
       m.month,
       SUM(p.sum_payment, 0) OVER(PARTITION BY c.customer 
                                  ORDER     BY m.month) AS sum_payment
FROM       months    m
CROSS JOIN customers c
LEFT JOIN  payments  p
       ON m.month = MONTH(p.date_)
      AND c.customer = p.customer
      AND YEAR(p.date_) = 2020
ORDER BY c.customer_name, m.month

您可以跳过查询中的最后一个ORDER BY子句:只是为了视觉化。
检查演示here

注意:“* 如果买家某个月没有付款,则显示“付款不存在”。*”。你不能这么做每个字段仅与一个类型相关联。你需要决定它是一个字符串还是一个整数。我建议您将其保留为integer,因为它是该字段应该存储的内容。如果您不希望使用NULL值,而希望使用零,则可以将SUM(p.sum_payment)更改为SUM(COALESCE(p.sum_payment, 0))

nx7onnlm

nx7onnlm2#

您可以首先使用递归cte生成月份,然后将付款和客户加入其中,计算每个客户和月份的总和。如果给定的月客户对不存在总和,则可以包含'payments do not exists'

with recursive cte(d) as (
   select cast('2020-01-01' as date)
   union all
   select c.d + interval 1 month from cte c where extract(month from c.d) < 12
)
select t.d, c.customer_name, case when t.s is null then 'payments do not exists' else t.s end 
from (
    select c.d, c1.customer, sum(p.sum_payment) s from cte c 
    cross join customers c1 
    left join payments p on p.customer = c1.customer and year(c.d) = year(p.date) and month(c.d) = month(p.date)
    group by c.d, c1.customer) t
join customers c on c.customer = t.customer
order by t.customer, t.d

See fiddle

相关问题