【问题标题】:Sum a subquery and group by customer info按客户信息汇总子查询和分组
【发布时间】:2009-05-12 21:37:34
【问题描述】:

我有三个类似以下的表:

Customer (CustomerID, AddressState)
Account (AccountID, CustomerID, OpenedDate)
Payment (AccountID, Amount)

付款表可以包含一个帐户的多个付款,一个客户可以有多个帐户。

我想做的是按州逐月检索所有付款的总金额。例如

Opened Date| State | Total
--------------------------
2009-01-01 |   CA  | 2,500
2009-01-01 |   GA  | 1,000
2009-01-01 |   NY  |   500
2009-02-01 |   CA  | 1,500
2009-02-01 |   NY  | 2,000

换句话说,我试图找出各州每月支付的费用最多。我只对 OpenedDate 的月份感兴趣,但我将其作为之后处理的日期。我试图在一个查询中检索我需要的所有数据。

我一直在尝试以下方式:

select
  dateadd (month, datediff(month, 0, a.OpenedDate), 0) as 'Date',
  c.AddressState as 'State',
  (
    select sum(x.Amount)
    from (
      select p.Amount
      from Payment p
      where p.AccountID = a.AccountID
    ) as x
  )
  from Account a
  inner join Customer c on c.CustomerID = a.CustomerID
  where ***
  group by
    dateadd(month, datediff(month, 0, a.OpenedDate), 0),
    c.AddressState

where 子句包括 Account 表中的一些常规内容。该查询将不起作用,因为 a.AccountID 未包含在聚合函数中。

我是否以正确的方式处理这个问题?如何检索我需要的数据以计算哪些州的客户支付最多?

【问题讨论】:

    标签: sql sql-server


    【解决方案1】:

    如果要按月分组数据,则需要按月分组:

    SELECT  AddressState, DATEPART(mm, OpenedDate), SUM(Amount)
    FROM    Customer c
    INNER JOIN Account a  ON a.CustomerID = c.CustomerID
    INNER JOIN Payments p ON p.AccountID = a.AccountID
    GROUP BY   AddressState, DATEPART(mm, OpenedDate)
    

    这会向您显示月份编号 (1-12) 和每个州的总金额。请注意,此示例不包括年份:无论年份如何,第 1 个月的所有金额都会相加。如果你愿意,可以添加一个 datepart(yy, OpenedDate)。

    【讨论】:

    • +1 简单的解决方案,可以包括过去半年的过滤器或按年分组。
    • 我想我把它复杂化了。使用此解决方案并将其与 dateadd(datediff()) 和我的 where 子句结合使用。如果您想知道为什么我更喜欢 dateadd(datediff()) 按月分组,请参阅 weblogs.sqlteam.com/jeffs/archive/2007/09/10/…
    【解决方案2】:

    换句话说,我试图找出各州每月支付的最高费用

    这个会选择每个月最赚钱的州:

    SELECT  *
    FROM    (
            SELECT  yr, mon, AddressState, amt, ROW_NUMBER() OVER (PARTITION BY yr, mon, addressstate ORDER BY amt DESC) AS rn
            FROM    (
                    SELECT  YEAR(OpenedDate) AS yr, MONTH(OpenedDate) AS mon, AddressState, SUM(Amount) AS amt
                    FROM    Customer c
                    JOIN    Account a
                    ON      a.CustomerID = c.CustomerID
                    JOIN    Payments p
                    ON      p.AccountID = a.AccountID
                    GROUP BY
                            YEAR(OpenedDate), MONTH(OpenedDate), AddressState
                    )
            ) q
    WHERE   rn = 1
    

    将最后一个条件替换为 ORDER BY yr, mon, amt DESC 以获取所有状态的列表,例如您的结果集中:

    SELECT  *
    FROM    (
            SELECT  yr, mon, AddressState, amt, ROW_NUMBER() OVER (PARTITION BY yr, mon, addressstate ORDER BY amt DESC) AS rn
            FROM    (
                    SELECT  YEAR(OpenedDate) AS yr, MONTH(OpenedDate) AS mon, AddressState, SUM(Amount) AS amt
                    FROM    Customer c
                    JOIN    Account a
                    ON      a.CustomerID = c.CustomerID
                    JOIN    Payments p
                    ON      p.AccountID = a.AccountID
                    GROUP BY
                            YEAR(OpenedDate), MONTH(OpenedDate), AddressState
                    )
            ) q
    ORDER BY
            yr, mon, amt DESC
    

    【讨论】:

    • 看起来不错,只需要在SELECT的Amount字段周围加上SUM()
    【解决方案3】:
    select
        AddressState,
        year(OpenedDate) as Yr,
        month(OpenedDate) as Mnth,
        sum(Payment) as SumPayment
    from Customer c
        inner join Account a
            on c.CustomerID=a.CustomerID
        inner join Payment p
            on a.AccountID=p.AccountID
    group by AddressState, month(OpenedDate)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-08
      • 2021-05-05
      • 2019-03-19
      • 1970-01-01
      相关资源
      最近更新 更多