每种类型的每个客户每年的汇总付款

时间:2017-11-27 10:15:45

标签: sql sql-server sql-server-2012

请考虑以下付款数据:

customerID    paymentID    pamentType    paymentDate    paymentAmount
---------------------------------------------------------------------
     1            1            A         2015-11-28          500
     1            2            A         2015-11-29         -150
     1            3            B         2016-03-07          300
     2            4            A         2015-03-03          200
     2            5            B         2016-05-25         -100
     2            6            C         2016-06-24          700
     1            7            B         2015-09-22          110
     2            8            B         2016-01-03          400

我需要按照每位客户计算各种付款类型(A =发票,B =贷方通知单等)的总和,如下所示:

year    customerID    paymentType    paymentSum
-----------------------------------------------
2015        1             A             350      : paymentID 1 + 2
2015        1             B             110      : paymentID 7
2015        1             C               0
2015        2             A             200      : paymentID 4
2015        2             B               0
2015        2             C               0
2016        1             A               0
2016        1             B             300      : paymentID 3
2016        1             C               0
2016        2             A               0
2016        2             B             300      : paymentID 5 + 8
2016        2             C             700      : paymentId 6

重要的是每个类别都有值(因此对于2015年,客户1对于C类有0个付款值,但仍然很高兴看到这个)。

实际上,有超过10种支付类型和约30个客户。总日期范围为10年。

这是否可以仅在SQL中执行,如果是这样,有人可以告诉我如何?如果可能的话,使用相对简单的查询,以便我可以从中学习,例如将中间结果存储到#temptable中。

非常感谢任何帮助!

2 个答案:

答案 0 :(得分:3)

paymentAmount上带有SUM()的简单GROUP BY将为您提供所需的内容

select  year = datepart(year, paymentDate),
        customerID,
        paymentType,
        paymentSum = sum(paymentAmount)
from    payment_data
group by datepart(year, paymentDate), customerID, paymentType

答案 1 :(得分:2)

这是一个生成所需0的简单查询。请注意,它可能不是生成此结果集的最高效方式。如果您已经拥有客户或付款类型的查找表,那么最好使用那些而不是我在这里使用的CTE 1

declare @t table (customerID int,paymentID int,paymentType char(1),paymentDate date,
                 paymentAmount int)
insert into @t(customerID,paymentID,paymentType,paymentDate,paymentAmount) values
(1,1,'A','20151128', 500),
(1,2,'A','20151129',-150),
(1,3,'B','20160307', 300),
(2,4,'A','20150303', 200),
(2,5,'B','20160525',-100),
(2,6,'C','20160624', 700),
(1,7,'B','20150922', 110),
(2,8,'B','20160103', 400)

;With Customers as (
    select DISTINCT customerID from @t
), PaymentTypes as (
    select DISTINCT paymentType from @t
), Years as (
    select DISTINCT DATEPART(year,paymentDate) as Yr from @t
), Matrix as (
    select
        customerID,
        paymentType,
        Yr
    from
        Customers
            cross join
        PaymentTypes
            cross join
        Years
)
select
    m.customerID,
    m.paymentType,
    m.Yr,
    COALESCE(SUM(paymentAmount),0) as Total
from
    Matrix m
        left join
    @t t
        on
            m.customerID = t.customerID and
            m.paymentType = t.paymentType and
            m.Yr = DATEPART(year,t.paymentDate)
group by
    m.customerID,
    m.paymentType,
    m.Yr

结果:

customerID  paymentType Yr          Total
----------- ----------- ----------- -----------
1           A           2015        350
1           A           2016        0
1           B           2015        110
1           B           2016        300
1           C           2015        0
1           C           2016        0
2           A           2015        200
2           A           2016        0
2           B           2015        0
2           B           2016        300
2           C           2015        0
2           C           2016        700

(如果上述日期处理需要能够使用索引,我们可能还希望玩数字表和/或生成多年的实际开始和结束日期)

另请注意我的脚本顶部与您问题中的示例数据有多相似 - 除了它是生成示例数据的实际代码。您可能希望考虑在将来以这种方式呈现示例代码,因为它简化了实际能够在答案中测试脚本的过程。

1 CTE - 通用表格表达式。它们可能被认为是概念上类似于临时表 - 除了我们实际上(必然)实现结果。它们也被合并到跟随它们的单个查询中,整个查询作为一个整体进行优化。

您建议使用临时表意味着您要将其分解为多个单独的查询,这些查询必然会强制SQL按我们选择的顺序执行任务,而不是让优化器为上述单个查询选择最佳方法。