【问题标题】:Sum value for each end of month每个月底的总和值
【发布时间】:2022-01-25 01:00:05
【问题描述】:

我有两张桌子。

具有 CustomerID、InternalID 和 AsOfDate 的表 A。

具有 InternalID、Spend、StoreNum 和 AsOfDate 的表 B。

我希望创建一个输出,以便我获得过去 12 个月每月最后一天的每个 CustomerID 的支出总和。一个月的最后一天不是 30 或 31,它是按工作日计算的,所以我想要一个查询,查找每个月内的 MAX 日期以确定最后一天。

带有数据和查询的示例表。

Declare @MAXDATE DATETIME
Select @MAXDATE = MAX (as_of_date) from table2 

select
  s.customerID,
  sum(case when s.asofdate = CAST('11/29/21' AS DATETIME) then hn.spend end) as val_prevmonth,
  sum(case when s.asofdate = @MAXDATE then hn.spend end) as val_curr
from table1 s
join table2 hn on hn.asofdate = s.asofdate 
                 and hn.internalID = s.internalID
where 
and  (s.asofdate = CAST('11/30/21' AS DATETIME) or s.asofdate = @MAXDATE)
group by s.customerID
order by s.customerID;

表 A

CustomerID InternalID AsOfDate
610 016 11/30/2021
610 016 11/29/2021
610 016 11/28/2021
610 016 10/29/2021
610 016 10/15/2021
610 016 9/15/2021
610 016 9/14/2021
610 016 8/10/2021
725 527 11/30/2021
725 527 11/29/2021
725 527 11/28/2021
725 527 10/29/2021
725 527 10/15/2021
725 527 9/15/2021
725 527 9/14/2021
725 527 8/10/2021

表 B

Spend InternalID StoreNum AsOfDate
5000 016 123 11/30/2021
4000 016 321 11/30/2021
3000 016 456 11/28/2021
4500 016 654 10/29/2021
5000 016 789 10/15/2021
4000 016 756 9/15/2021
9000 016 987 9/15/2021
1000 016 545 8/10/2021
6000 527 124 11/30/2021
4500 527 354 11/30/2021
9000 527 745 11/28/2021
8500 527 846 10/29/2021
7500 527 646 10/29/2021
6000 527 311 9/14/2021
3000 527 211 9/14/2021
2500 527 121 8/10/2021

表 C。注意 CustomerID 725 从 9 月开始丢失,因为他们在 9 月的最后一个工作日(即 15 日)没有进行任何交易。列名也不需要包含日期,为了清楚起见,我把它放在那里。

CustomerID 11/30/2021 TotalSpend 10/29/2021 TotalSpend 9/15/2021 TotalSpend 8/10/2021 TotalSpend
610 9000 4500 1300 1000
725 10500 16000 2500

【问题讨论】:

  • 您想要每个月只有一天的数据?您希望列出所有客户,即使他们没有数据?将 TableC 结果加入到所有客户的表中。列名必须具有使其唯一性。
  • 你是对的 - 它是 sql-server!感谢您指出这一点
  • 好的,标签已更改。还有一个额外的答案。

标签: sql sql-server


【解决方案1】:

您可以在 MS Sql Server 中以年月为轴。

SELECT *
FROM (
  SELECT 
    CustomerID
  , FORMAT(MAX(AsOfDate), 'yyyy-MM')+' Total Spend' AS Col
  , SUM(Spend) AS TotalSpend
  FROM
  (
    SELECT 
      t1.*
    , t2.Spend
    , t2.StoreNum
    , rnk = DENSE_RANK() OVER (PARTITION BY t1.InternalID, EOMONTH(t1.AsOfDate) ORDER BY t1.AsOfDate DESC)
    FROM Table1 t1
    JOIN Table2 t2
      ON t2.InternalID = t1.InternalID
     AND t2.AsOfDate = t1.AsOfDate
    WHERE t1.AsOfDate >= DATEADD(year,-1,DATEADD(month,-1,DATEADD(day,1,EOMONTH(GETDATE()))))
      AND t2.AsOfDate >= DATEADD(year,-1,DATEADD(month,-1,DATEADD(day,1,EOMONTH(GETDATE()))))
  ) q
  WHERE rnk = 1
  GROUP BY CustomerID, EOMONTH(AsOfDate)
) Src
PIVOT (
  SUM(TotalSpend)
  FOR Col IN (
    [2021-11 Total Spend]
  , [2021-10 Total Spend]
  , [2021-09 Total Spend]
  , [2021-08 Total Spend]
  )
) Pvt
ORDER BY CustomerID;

【讨论】:

    【解决方案2】:

    已更新 - 我已将答案修改为目标 SQL Server。

    我们首先获取我们正在查看的期间的 CustomerID 列表 -

    SELECT DISTINCT CustomerID
    FROM TableA
    WHERE AsOfDate > NOW() - INTERVAL 1 YEAR
    

    我们会做类似的事情来获取过去一年该月最后一个交易日的列表,然后应用 ROW_NUMBER(),这样我们就有了从 1 到 12 的唯一数字来处理数据透视表。

    SELECT ROW_NUMBER() OVER(ORDER BY MAX(AsOfDate) DESC) AS RowNum, MAX(AsOfDate) EndOfMonth
    FROM TableA
    WHERE AsOfDate > NOW() - INTERVAL 1 YEAR
    GROUP BY YEAR(AsOfDate), MONTH(AsOfDate)
    ORDER BY EndOfMonth ASC
    

    然后,我们将上述查询作为两个派生表与一个 CROSS JOIN 组合在一起,以提供笛卡尔积,然后将左连接与 TableA 和 TableB。

    WITH customers (CustomerID) AS (
        SELECT DISTINCT CustomerID
        FROM TableA
        WHERE AsOfDate > DATEADD(year, -1, GETDATE())
    ), months (RowNum, EndOfMonth) AS (
        SELECT ROW_NUMBER() OVER(ORDER BY MAX(AsOfDate) DESC) AS RowNum, MAX(AsOfDate) EndOfMonth
        FROM TableA
        WHERE AsOfDate > DATEADD(year, -1, GETDATE())
        GROUP BY YEAR(AsOfDate), MONTH(AsOfDate)
    )
    SELECT
        customers.CustomerID,
        SUM(CASE WHEN months.RowNum =  1 THEN TableB.Spend END) AS TotalSpend1,
        SUM(CASE WHEN months.RowNum =  2 THEN TableB.Spend END) AS TotalSpend2,
        SUM(CASE WHEN months.RowNum =  3 THEN TableB.Spend END) AS TotalSpend3,
        SUM(CASE WHEN months.RowNum =  4 THEN TableB.Spend END) AS TotalSpend4,
        SUM(CASE WHEN months.RowNum =  5 THEN TableB.Spend END) AS TotalSpend5,
        SUM(CASE WHEN months.RowNum =  6 THEN TableB.Spend END) AS TotalSpend6,
        SUM(CASE WHEN months.RowNum =  7 THEN TableB.Spend END) AS TotalSpend7,
        SUM(CASE WHEN months.RowNum =  8 THEN TableB.Spend END) AS TotalSpend8,
        SUM(CASE WHEN months.RowNum =  9 THEN TableB.Spend END) AS TotalSpend9,
        SUM(CASE WHEN months.RowNum = 10 THEN TableB.Spend END) AS TotalSpend10,
        SUM(CASE WHEN months.RowNum = 11 THEN TableB.Spend END) AS TotalSpend11,
        SUM(CASE WHEN months.RowNum = 12 THEN TableB.Spend END) AS TotalSpend12
    FROM customers
    CROSS JOIN months
    LEFT JOIN TableA
        ON customers.CustomerID = TableA.CustomerID
        AND months.EndOfMonth = TableA.AsOfDate
    LEFT JOIN TableB
        ON TableA.InternalID = TableB.InternalID
        AND TableA.AsOfDate = TableB.AsOfDate
    GROUP BY customers.CustomerID
    ORDER BY customers.CustomerID ASC;;
    

    这是db<>fiddle

    如果您想在结果中包含每个月的最后一个交易日,您可以将 SELECT 列表更改为 -

    SELECT
        customers.CustomerID,
        MAX(CASE WHEN months.RowNum =  1 THEN months.EndOfMonth END) AS `Month1`,
        SUM(CASE WHEN months.RowNum =  1 THEN TableB.Spend END) AS `TotalSpend1`,
        MAX(CASE WHEN months.RowNum =  2 THEN months.EndOfMonth END) AS `Month2`,
        SUM(CASE WHEN months.RowNum =  2 THEN TableB.Spend END) AS `TotalSpend2`,
        ...
    

    【讨论】:

    • 嗨 - 感谢您抽出宝贵的时间来回答。我正在尝试使用您的类似方法,但正如其他人指出的那样,我在 SQL-server 上。您是否有使用该语法的经验?
    • SQL Server 有很多不喜欢的地方 - 标识符的反引号、NOW()、JOIN without criteria 而不是显式 CROSS JOIN...现在应该可以正常工作了。
    • @Motacular 在我进行最后一次更改后它对你有用吗?
    猜你喜欢
    • 2023-01-08
    • 2012-12-08
    • 1970-01-01
    • 2021-08-21
    • 1970-01-01
    • 2018-06-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多