【问题标题】:return amount per year/month records based on start and enddate基于开始和结束日期的年/月记录返回金额
【发布时间】:2019-09-18 11:05:24
【问题描述】:

我有一个表格,例如以下数据:

ID |start_date  |end_date   |amount
---|------------|-----------|--------
1  |2019-03-21  |2019-05-09 |10000.00
2  |2019-04-02  |2019-04-10 |30000.00
3  |2018-11-01  |2019-01-08 |20000.00

我希望根据年/月以正确的计算量取回拆分的记录。

我希望结果是这样的:

ID |month |year   |amount
---|------|-------|--------
1  |3     | 2019  | 2200.00
1  |4     | 2019  | 6000.00
1  |5     | 2019  | 1800.00
2  |4     | 2019  |30000.00
3  |11    | 2018  | 8695.65
3  |12    | 2018  | 8985.51
3  |1     | 2019  | 2318.84

实现这一目标的最佳方法是什么?我认为您必须使用 DATEDIFF 来获取 start_date 和 end_date 之间的天数来计算每天的金额,但我不知道如何将其作为每月/每年的记录返回。

Tnx 提前!

【问题讨论】:

  • 你有日历表吗,或者你可以创建一个吗?

标签: sql-server tsql date-range


【解决方案1】:

这是一个想法。我使用 Tally 为与 ID 相关的每一天创建一天。然后,我汇总Amount 的值除以天数,天数按月份和年份分组:

CREATE TABLE dbo.YourTable(ID int,
                           StartDate date,
                           EndDate date,
                           Amount decimal(12,2));
GO
INSERT INTO dbo.YourTable (ID,
                           StartDate,
                           EndDate,
                           Amount)
VALUES(1,'2019-03-21','2019-05-09',10000.00),
      (2,'2019-04-02','2019-04-10',30000.00),
      (3,'2018-11-01','2019-01-08',20000.00);
GO
--Create a tally
WITH N AS(
    SELECT N
    FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N(N)),
Tally AS(
    SELECT TOP (SELECT MAX(DATEDIFF(DAY, t.StartDate, t.EndDate)+1) FROM dbo.YourTable t) --Limits the rows, might be needed in a large dataset, might not be, remove as required
           ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) -1 AS I
    FROM N N1, N N2, N N3), --1000 days, is that enough?
--Create the dates
Dates AS(
    SELECT YT.ID,
           DATEADD(DAY, T.I, YT.StartDate) AS [Date],
           YT.Amount,
           COUNT(T.I) OVER (PARTITION BY YT.ID) AS [Days]
    FROM Tally T
         JOIN dbo.YourTable YT ON T.I <= DATEDIFF(DAY, YT.StartDate, YT.EndDate))
--And now aggregate
SELECT D.ID,
       DATEPART(MONTH,D.[Date]) AS [Month],
       DATEPART(YEAR,D.[Date]) AS [Year],
       CONVERT(decimal(12,2),SUM(D.Amount / D.[Days])) AS Amount
FROM Dates D
GROUP BY D.ID,
         DATEPART(MONTH,D.[Date]),
         DATEPART(YEAR,D.[Date])
ORDER BY D.ID,
         [Year],
         [Month];

GO

DROP TABLE dbo.YourTable;
GO

DB<>Fiddle

【讨论】:

  • 谢谢!这在我的本地数据库上非常有效且快速。它立即加载。在我的 SQL Azure DB 上远程使用完全相同的数据大约需要 10 秒。你知道这怎么可能吗?该查询返回大约 9000 行。
  • 如果它是远程的,它可能只是您通过 WAN 下载数据集的时候了。不知道你的上下车速度怎么样。如果您 INSERT(如果您愿意,可以使用 INTO 到一个临时表)将数据放入另一个表(这样您就不会将数据集返回给自己),如果答案机会更快?
  • 这似乎不是问题。在 SQL Azure 上,查询的执行时间确实很长。甚至大约 15 秒。
  • Azure 中服务器上的索引 lacl?也许你有一个非常低规格的 Azure 服务器,@Stackberg?问题似乎是您正在使用的服务器的性能,而不是 SQL(我对设计良好的数据库和高性能实例的性能非常有信心)。这肯定会大大优于 rCTE 解决方案。
  • 为了确保我拥有完全相同的数据库、相同的索引和相同的数据,我将我的 Sql Azure 提取为数据层应用程序并在本地导入。我有一个低规格的 Azure 服务器,但我认为这不会将性能从即时结果降低到 15 秒。
猜你喜欢
  • 1970-01-01
  • 2020-01-05
  • 2014-03-02
  • 1970-01-01
  • 2022-12-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多