【问题标题】:Aggregate payments per year per customer per type每种类型的每位客户每年的总付款
【发布时间】:2017-11-27 18:37:05
【问题描述】:

请考虑以下付款数据:

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 中。

非常感谢任何帮助!

【问题讨论】:

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


    【解决方案1】:

    在 paymentAmount 上使用 SUM() 的简单 GROUP BY 将为您提供您想要的

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

    【讨论】:

      【解决方案2】:

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

      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
      

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


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


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

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

      【讨论】:

        猜你喜欢
        • 2022-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-01-13
        • 2016-06-11
        • 2022-01-05
        • 2021-02-18
        • 2022-12-11
        相关资源
        最近更新 更多