N 天的总和,不包括周末和节假日
Posted
技术标签:
【中文标题】N 天的总和,不包括周末和节假日【英文标题】:Sum over N days excluding Weekends and Holidays 【发布时间】:2021-10-31 21:44:09 【问题描述】:我有下表
AccountID | Date | Amount |
---|---|---|
123 | 07/02/2021 | 2000 |
123 | 07/09/2021 | 9000 |
123 | 07/15/2021 | 500 |
123 | 07/20/2021 | 500 |
123 | 07/28/2021 | 500 |
我正在尝试创建一个测试脚本来测试一个月(7 月)的数据。我想合计 5 天的金额,其中 5 天不包括周末和节假日。由于是 7 月,因此假期在 2021 年 7 月 5 日(07/05/2021)。
输出应该如下所示
AccountID | Date | Amount |
---|---|---|
123 | 07/02/2021 | 11000 |
123 | 07/09/2021 | 9500 |
123 | 07/15/2021 | 1000 |
123 | 07/20/2021 | 500 |
123 | 07/28/2021 | 500 |
下面是表创建和数据插入语句供参考:-
create table TRANSACTIONS (
AccountID int,
Date date,
Amount int
)
insert into TRANSACTIONS values (123, '07/02/2021', 2000)
insert into TRANSACTIONS values (123, '07/09/2021', 9000)
insert into TRANSACTIONS values (123, '07/15/2021', 500)
insert into TRANSACTIONS values (123, '07/20/2021', 500)
insert into TRANSACTIONS values (123, '07/28/2021', 500)
我能够创建可以跳过周末(周六和周日)超过 5 天的脚本。我想不出我怎么能跳过 2021 年 7 月 5 日的假期。我可以硬编码它,因为这只是为了测试目的。代码 'DATEPART(WEEKDAY, h2.Date) not in (1, 7)
' 跳过周末和 'DATEADD(d, 6, h1.Date)'
在这里我添加 6 而不是 5,即使总和应该超过 5 天,因为在阅读了一些文章后,我认为在跳过周末时最后一天不包括在内,所以使用 6而不是 5。这段代码完美地添加了超过 5 天的跳过周末
SELECT AccountId, Date,
(
SELECT SUM(Amount)
FROM TRANSACTIONS h2
WHERE
h1.AccountID = h2.AccountID and
DATEPART(WEEKDAY, h2.Date) not in (1, 7) and
h2.Date between h1.Date AND DATEADD(d, 6, h1.Date)
) as SumAmount
FROM TRANSACTIONS h1
【问题讨论】:
解决这个问题的唯一明智的方法是有一个日历表来表示假期。最简单的方法是存储您可能需要的日期范围(例如 1970-2030)的每个日期,日期类型可能为WORKDAY
、WEEKEND
的枚举, HOLIDAY
或任何有效的方法。根据您居住的地方,您可能还需要包含 region 列(通常是国家和/或州)
就像我提到的,我只需要测试 2021 年 7 月的月份,而 2021 年 7 月 5 日只有一个假期。周末我能够弄清楚并使用 datepart(dw,date)) 不是在 (1,7) 中。如果我有 2021 年 7 月 5 日的表格,您能否也解释一下逻辑,我如何计算跳过此日期的 5 天?我已经提到了我创建的查询,我可以在计算 5 天时跳过周末
“假期”是指Elbonian 日历上泥浆深度大于0.5 Smoot 的任何事件吗?也许只是美国新罕布什尔州的银行假期?提示:( @@DateFirst + DatePart( weekday, SampleDate ) - 1 ) % 7 + 1
将始终返回一个从1
到7
的整数,其中1
对应于星期日,无论DateFirst
或Language
的设置如何。
我的意思是美国的银行假期,比如 2021 年 7 月 5 日。因为我只在 7 月进行测试。我需要一种方法来排除这一天。周末我已经在使用 DATEPART(WEEKDAY, h2.Date) 而不是 (1, 7)
您需要一个包含每个日期的完整日历,而不仅仅是“假期”。真正完整的日历表有很多用途。我们不要忽视这样一个事实,即周末和节假日并不是唯一没有完成“工作”的日子。疏散?自然灾害?失去动力?受感染的网络导致关闭?
【参考方案1】:
解决此问题的唯一明智方法是使用日历表来表示假期。最简单的方法是存储您可能需要的日期范围(例如 1970-2030)的每个日期,日期类型可能是工作日、周末、假日或其他任何有效的枚举,例如
CREATE TABLE CALENDAR (
Date DATE,
Day_type varchar(16)
);
-- insert rows for dates you care about
根据您的居住地,您可能还需要包含地区列(通常是国家和/或州)。
有了这样一个表,你就加入它:
SELECT
AccountId,
DATEADD(DAY, (DATEDIFF(DAY, 0, t.Date)/7)*7 + 7, 0) as Date,
SUM(Amount)
FROM TRANSACTIONS t
JOIN CALENDAR c on t.Date = c.Date
AND c.day_type = 'WORKDAY'
WHERE t.Date BETWEEN <your date range>
GROUP BY AccountId, DATEADD(DAY, (DATEDIFF(DAY, 0, t.Date)/7)*7 + 7, 0)
【讨论】:
我认为在周末使用 'DATEPART(WEEKDAY, h2.Date) not in (1, 7)' 是一种非常简单易行的方法,并且需要创建一个表。我不确定我们如何排除假期 @rohitpandey 但代码更多。使用日历表,您无需编码或记住此类表达式 你能解释一下你想在这里做什么'DATEADD(DAY, (DATEDIFF(DAY, 0, t.Date)/7)*7 + 7, 0)'。因为对于日期,我想要第一笔交易的那一天?就像我在所需的输出中提到的那样以上是关于N 天的总和,不包括周末和节假日的主要内容,如果未能解决你的问题,请参考以下文章