【问题标题】:SQL query for calculating mtd, ytd values用于计算 mtd、ytd 值的 SQL 查询
【发布时间】:2016-08-31 07:22:38
【问题描述】:

我有一张表,其中包含 IDTitleDateAmount 列。

我需要根据TitleDate 获取每笔交易的 MTD、YTD 金额值。

以前有人做过吗?

【问题讨论】:

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


【解决方案1】:
Select t.title, t.Date, 
  Sum(y.Amount) YTD,
  Sum(m.Amount) MTD
From table t
   left join table y
      on y.Title = t.Title
         and datediff(year, y.Date, t.Date) = 0 
         and y.Date <= t.Date
  left join table m
      on m.Title = t.Title
         and datediff(month, m.Date, t.Date) = 0 
         and m.Date <= t.Date
         and m.Date <> y.Date
Group by t.title, t.Date

【讨论】:

  • 谢谢!真的很有帮助
  • 这不是一个正确的答案,因为每个连接都会乘以 SUM 计算中使用的行数。假设我们有一个只有 2 行的小桌子。每行具有相同的标题,但在同一月份和年份中的日期不同。那么对于第一个日期,将只有 1 行用于 SUM,因为 t 行 * y 行 * m 行 = 1 * 1 * 1 = 1,但对于第二个日期,将有 4 行 - 1 * 2 * 2 . 因此,如果行中的金额分别为 2 和 3,您将得到 MTD = 10 和 YTD = 10,实际上应该是 5 和 5。
  • @Peter,我认为 OP 的问题询问有关 Month“to Date”和 year“to Date”值的事实解释了使用
  • @CharlesBretana,我了解 SQL Fiddle。第二行的 YTD 和 MTD 金额应分别为 5 和 5,而不是 10 和 10。
  • @Peter,是的,你是对的,我认为它们需要左连接,并且第二个连接表需要排除日期与第一个连接日期相同的行。这似乎可以解决您的示例数据,我正在努力确定它是否也适用于其他场景。谢谢!
【解决方案2】:

接受的解决方案不正确。假设我们有一个下表:

ID   Title   Date        Amount
---  ------  ----------  ------
  1  Cust A  2020-01-01    2.00
  2  Cust A  2020-01-05    3.00
  3  Cust A  2020-02-01    5.00

接受的答案会给我们以下结果:

Title   Date        YTD    MTD
------  ----------  -----  -----
Cust A  2021-01-01   2.00   2.00
Cust A  2021-01-05  10.00  10.00
Cust A  2021-02-01  10.00  15.00

这是因为每个连接都会将记录数乘以匹配记录数。删除聚合后可以很容易地看到这一点:

Select t.title, t.Date, y.Date, m.Date,
  y.Amount,
  m.Amount
From [table] t
   join [table] y
      on y.Title = t.Title
         and datediff(year, y.Date, t.Date) = 0 
         and y.Date <= t.Date
   join [table] m
      on m.Title = t.Title
         and datediff(month, m.Date, t.Date) = 0 
         and m.Date <= t.Date
Order by t.title, t.Date, y.Date, m.Date

结果:

Title   t.Date      y.Date      m.Date      y.Amount    m.Amount
-----   ----------  ----------  ----------  --------    --------
Cust A  2021-01-01  2021-01-01  2021-01-01         2           2
Cust A  2021-01-05  2021-01-01  2021-01-01         2           2
Cust A  2021-01-05  2021-01-01  2021-01-05         2           3
Cust A  2021-01-05  2021-01-05  2021-01-01         3           2
Cust A  2021-01-05  2021-01-05  2021-01-05         3           3
Cust A  2021-02-01  2021-01-01  2021-02-01         2           5
Cust A  2021-02-01  2021-01-05  2021-02-01         3           5
Cust A  2021-02-01  2021-02-01  2021-02-01         5           5

这是一个修改后的选择,可以产生正确的结果:

Select a.title, a.Date, 
  Sum(Case When datediff(year, b.Date, a.Date) = 0 Then b.Amount Else 0 End) YTD,
  Sum(Case When datediff(month, b.Date, a.Date) = 0 Then b.Amount Else 0 End) MTD
From [table] a
   join [table] b
      on a.Title = b.Title
         and b.Date <= a.Date
Group by a.title, a.Date

结果:

Title   Date        YTD    MTD
------  ----------  -----  -----
Cust A  2021-01-01   2.00   2.00
Cust A  2021-01-05   5.00   5.00
Cust A  2021-02-01  10.00   5.00

这是SQL Fiddle,其中包含所有当前答案以及新的解决方案。

【讨论】:

  • 嗨彼得,你的最终解决方案是一个救生员和一个改变游戏规则的人。我为 Daily、Monthly 和 Yearly 编写了大型 CTE,然后将所有 CTE 结合起来得到相同的结果……但这只是一个优雅的解决方案。谢谢!
【解决方案3】:
SELECT ID,
       Title,
       Date,
       Amount,
       MTD  = SUM(Amount) OVER (PARTITION BY Title, DATEADD(MONTH, DATEDIFF(MONTH, 0, [Date]), 0)),
       YTD  = SUM(Amount) OVER (PARTITION BY Title, DATEADD(YEAR, DATEDIFF(YEAR, 0, [Date]), 0))
FROM   [a_table]

【讨论】:

  • 谢谢!真的很有帮助
  • 这似乎得到了完整的总数,而不是运行总数。我的意思是,YTD 对一年中的所有记录具有相同的值(年度总计),而不是仅前几个月的记录的总计。
猜你喜欢
  • 2011-11-04
  • 2022-06-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-27
  • 1970-01-01
  • 1970-01-01
  • 2021-02-09
相关资源
最近更新 更多