我陷入了SQL查询中。
我正在尝试在同一查询中计算两个不同的事物:
让我们说11月(截至2018年11月9日)
no.of business days no. of business days passed
22 7
我尝试过这样:
WITH cteAllDates AS
(
DECLARE @StartDate DATETIME
DECLARE @EndDate DATETIME
SET @StartDate = '10/01/2018'
SET @EndDate = '10/31/2018'
SELECT
(DATEDIFF(dd, @StartDate, @EndDate) + 1)
- (DATEDIFF(wk, @StartDate, @EndDate) * 2)
- (CASE WHEN DATENAME(dw, @StartDate) = 'Sunday' THEN 1 ELSE 0 END)
- (CASE WHEN DATENAME(dw, @EndDate) = 'Saturday' THEN 1 ELSE 0 END) AS x
) AS y
SELECT x
FROM cteAllDates
我想创建一个虚拟表,以便可以在完整查询中使用这些字段。而且,如果可以的话,我可以使用GETDATE()
进行此操作,而不必每次都声明日期。
答案 0 :(得分:1)
由于您要在CTE中进行此操作,并且基于您在SO上找到的较早答案,因此以下版本可以在当月完成所有操作,而无需定义开始日期和结束日期:
编辑:创建假期表
首先,创建一个假期表。不要每次都这样做,使其成为一个持久的表,并使其充满您需要的所有假期-复活节,圣诞节等。
create table holidays(holiday date)
insert holidays values ('2018-09-23'),('2018-09-24')
现在查询,包括检查日期之间的假期数
;with dates as(
select dateadd(d,-day(getdate())+1,convert(date,getdate())) as startofmonth,
dateadd(d,-1,dateadd(m,1,dateadd(d,-day(getdate())+1,convert(date,getdate())))) as endofmonth,
convert(date,getdate()) as today
)
,holidaycount as (
select count(*) as holidaysinmonth,
sum(case when holiday<=today then 1 else 0 end) as holidaystodate
from dates
join holidays on holiday between startofmonth and endofmonth
)
,daycounts as(
select dates.*,
(DATEDIFF(dd, startofmonth, endofmonth) + 1)
-(DATEDIFF(wk, startofmonth, endofmonth) * 2)
-(CASE WHEN DATENAME(dw, startofmonth) = 'Sunday' THEN 1 ELSE 0 END)
-(CASE WHEN DATENAME(dw, endofmonth) = 'Saturday' THEN 1 ELSE 0 END)
-isnull(holidaysinmonth,0) as wkdaysinmonth,
(DATEDIFF(dd, startofmonth, today) + 1)
-(DATEDIFF(wk, startofmonth, today) * 2)
-(CASE WHEN DATENAME(dw, startofmonth) = 'Sunday' THEN 1 ELSE 0 END)
-(CASE WHEN DATENAME(dw, today) = 'Saturday' THEN 1 ELSE 0 END)
-isnull(holidaystodate,0) as wkdaystodate
from dates
cross join holidaycount
)
select * from daycounts
编辑:如果无法创建临时表,则将其作为假日计数之前的其他CTE添加:
,holidays as (
select holiday from (values ('2018-11-23'),('2018-11-24')) t(holiday)
)
,holidaycount as (
答案 1 :(得分:0)
您可以尝试使用cte递归创建日历表,然后使用条件聚合函数获取结果。
DECLARE @StartDate DATETIME
DECLARE @EndDate DATETIME
SET @StartDate = DATEADD(DAY, 1, EOMONTH(GETDATE(), -1));
SET @EndDate = DATEADD(DAY, 1, EOMONTH(GETDATE()));
;WITH CTE AS (
select @StartDate startdt,@EndDate enddt
UNION ALL
SELECT DATEADD (day ,1 , startdt) , @EndDate
FROM CTE
WHERE DATEADD (day,1,startdt) <= @EndDate
)
select SUM(CASE WHEN DATENAME(dw, startdt) NOT IN ('Sunday','Saturday') THEN 1 END) 'no.of business days',
SUM(CASE WHEN DATENAME(dw, startdt) NOT IN ('Sunday','Saturday') AND GETDATE() >= startdt THEN 1 END) 'no. of business days passed'
FROM CTE
结果
no.of business days no. of business days passed
22 7
答案 2 :(得分:0)
只要您需要一个月的数据,就可以在没有递归CTE的情况下执行此操作。
DECLARE @dt AS DATE = '2018-11-09';
WITH vars1 AS (
SELECT
d1 = DATEADD(dd, 1, EOMONTH(@dt, -1)),
dn = EOMONTH(@dt),
wks = DAY(@dt) / 7
), vars AS (
SELECT
d1, -- first day of month
dn, -- last day of month
wks, -- number of 7-day intervals elapsed
d29 = DATEADD(dd, 28, d1), -- 29th day of month
d30 = DATEADD(dd, 29, d1),
d31 = DATEADD(dd, 30, d1),
dp1 = DATEADD(dd, wks * 7 + 0, d1), -- wks * 7 gives you 0, 7, 14, 21 or 28
dp2 = DATEADD(dd, wks * 7 + 1, d1), -- wks * 7 + 0 ... 5 are the dates to check
dp3 = DATEADD(dd, wks * 7 + 2, d1),
dp4 = DATEADD(dd, wks * 7 + 3, d1),
dp5 = DATEADD(dd, wks * 7 + 4, d1),
dp6 = DATEADD(dd, wks * 7 + 5, d1)
FROM vars1
)
SELECT
[no. of business days] = 20 +
IIF(d29 <= dn AND DATENAME(dw, d29) NOT IN ('Saturday', 'Sunday'), 1, 0) +
IIF(d30 <= dn AND DATENAME(dw, d30) NOT IN ('Saturday', 'Sunday'), 1, 0) +
IIF(d31 <= dn AND DATENAME(dw, d31) NOT IN ('Saturday', 'Sunday'), 1, 0),
[no. of business days passed] = wks * 5 +
IIF(dp1 <= @dt AND DATENAME(dw, dp1) NOT IN ('Saturday', 'Sunday'), 1, 0) +
IIF(dp2 <= @dt AND DATENAME(dw, dp2) NOT IN ('Saturday', 'Sunday'), 1, 0) +
IIF(dp3 <= @dt AND DATENAME(dw, dp3) NOT IN ('Saturday', 'Sunday'), 1, 0) +
IIF(dp4 <= @dt AND DATENAME(dw, dp4) NOT IN ('Saturday', 'Sunday'), 1, 0) +
IIF(dp5 <= @dt AND DATENAME(dw, dp5) NOT IN ('Saturday', 'Sunday'), 1, 0) +
IIF(dp6 <= @dt AND DATENAME(dw, dp6) NOT IN ('Saturday', 'Sunday'), 1, 0)
FROM vars