Sql server T-SQL任务-查找两个日期范围内具有指定工作日的所有日期
在T-SQL MSSQL 2005中,我有一个非常艰巨的任务要做。我有一张这样的桌子:Sql server T-SQL任务-查找两个日期范围内具有指定工作日的所有日期,sql-server,sql-server-2005,tsql,Sql Server,Sql Server 2005,Tsql,在T-SQL MSSQL 2005中,我有一个非常艰巨的任务要做。我有一张这样的桌子: WeekDay| SlotTime ------------------ | 1 | 07:00 | 3 | 09:00 | 7 | 14:00 | 1 | 15:00 | 4 | 22:00 | 6 | 08:00 其中第一列是工作日编号,第二列是某个时间值 作为查询的参数,我有两个日期,例如: StartDate = '2011-07-20'
WeekDay| SlotTime
------------------
| 1 | 07:00
| 3 | 09:00
| 7 | 14:00
| 1 | 15:00
| 4 | 22:00
| 6 | 08:00
其中第一列是工作日编号,第二列是某个时间值
作为查询的参数,我有两个日期,例如:
StartDate = '2011-07-20'
EndDate = '2011-08-17'
这是我的数据的范围定义。我必须为这些范围生成上表中工作日发生的所有日期,并将SlotTime值添加到这些日期中。
例如,对于上述日期范围,结果列应为:
2011-07-20 9:00
2011-07-21 22:00
2011-07-23 8:00
2011-07-24 14:00
2011-07-25 7:00
2011-07-25 15:00
2011-07-27 9:00
2011-07-28 22:00
2011-07-30 8:00
etc.
...
你知道如何做到这一点吗?有什么建议吗我认为如果没有一些庞大的计算和额外的表格,这是不可能的
编辑此代码段可能会有所帮助
我玩这个函数是为了把它作为我计算的一部分,但无法实现我的目标。也许这其中的一部分可以用在最终的解决方案中
create function dbo.NthWeekDay(
@first datetime, -- First of the month of interest (no time part)
@nth tinyint, -- Which of them - 1st, 2nd, etc.
@dow tinyint -- Day of week we want
) returns datetime as begin
-- Note: Returns a date in a later month if @nth is too large
declare @result datetime
set @result = @first + 7*(@nth-1)
return @result + (7 + @dow - datepart(weekday,@result))%7
end
go
SET DATEFORMAT ymd
SET DATEFIRST 1
select dbo.NthWeekDay('2011-07-20',1,1) as D
go
drop function NthWeekDay
你可以使用所谓的数字表。只需创建一个表,其中的行数与日期之间的天数相同,并按顺序编号即可 下面是一种在SQL 2008中创建数字表的非常灵活的方法,也可以在2005年使用: 或者,您只需创建一个具有标识的表,然后将顶部的x行插入其中 从这里你可以计算出剩下的
number
1 DateAdd(dd, '2011/07/20', number) DatePart(dw, DateAdd(dd, '2011/07/20', number))
2 DateAdd(dd, '2011/07/20', number) DatePart(dw, DateAdd(dd, '2011/07/20', number))
3 DateAdd(dd, '2011/07/20', number) DatePart(dw, DateAdd(dd, '2011/07/20', number))
4 DateAdd(dd, '2011/07/20', number) DatePart(dw, DateAdd(dd, '2011/07/20', number))
5 DateAdd(dd, '2011/07/20', number) DatePart(dw, DateAdd(dd, '2011/07/20', number))
6 DateAdd(dd, '2011/07/20', number) DatePart(dw, DateAdd(dd, '2011/07/20', number))
7 DateAdd(dd, '2011/07/20', number) DatePart(dw, DateAdd(dd, '2011/07/20', number))
将该表连接到原始结果,然后将产品插入到最终表中
查询:
SELECT TOP 5000
IDENTITY( INT, 0, 1 ) AS N
INTO
Number
FROM
sys.objects a,
sys.objects b,
sys.objects c
SELECT
N,
DATEADD(dd, N, '7/20/2011') AS Date,
DATEPART(dw, DATEADD(dd, N, '7/20/2011')) AS DayofWeek
FROM
Number
WHERE
DATEADD(dd, N, '7/20/2011') BETWEEN '7/20/2011'
AND '8/17/2011'
结果:
N Date DayofWeek
----------- ----------------------- -----------
0 2011-07-20 00:00:00.000 4
1 2011-07-21 00:00:00.000 5
2 2011-07-22 00:00:00.000 6
3 2011-07-23 00:00:00.000 7
4 2011-07-24 00:00:00.000 1
5 2011-07-25 00:00:00.000 2
6 2011-07-26 00:00:00.000 3
7 2011-07-27 00:00:00.000 4
8 2011-07-28 00:00:00.000 5
9 2011-07-29 00:00:00.000 6
10 2011-07-30 00:00:00.000 7
11 2011-07-31 00:00:00.000 1
12 2011-08-01 00:00:00.000 2
13 2011-08-02 00:00:00.000 3
14 2011-08-03 00:00:00.000 4
15 2011-08-04 00:00:00.000 5
16 2011-08-05 00:00:00.000 6
17 2011-08-06 00:00:00.000 7
18 2011-08-07 00:00:00.000 1
19 2011-08-08 00:00:00.000 2
20 2011-08-09 00:00:00.000 3
21 2011-08-10 00:00:00.000 4
22 2011-08-11 00:00:00.000 5
23 2011-08-12 00:00:00.000 6
24 2011-08-13 00:00:00.000 7
25 2011-08-14 00:00:00.000 1
26 2011-08-15 00:00:00.000 2
27 2011-08-16 00:00:00.000 3
28 2011-08-17 00:00:00.000 4
这样就行了
SET DATEFIRST 1
-- temp table
declare @t table(WeekDay tinyint, SlotTime time)
-- fill table
insert @t values (1, '7:00')
insert @t values (3, '9:00')
insert @t values (7, '14:00')
insert @t values (1, '15:00')
insert @t values (4, '22:00')
insert @t values (6, '8:00')
-- declare interval
declare @startdate datetime
declare @enddate datetime
set @StartDate = '2011-07-20'
set @EndDate = '2011-08-17'
;with cte as
(
-- recusive to make timeline
SELECT @StartDate loopday
UNION ALL
SELECT loopday + 1
FROM cte
WHERE loopday < @EndDate
), b as
(
-- join timeline with Weekday and add Slottime to timeline
SELECT loopday + t.SlotTime col
FROM cte
JOIN @t t
ON t.WeekDay = datepart(weekday, cte.loopday)
)
SELECT col
FROM b
ORDER BY 1
OPTION( MAXRECURSION 0)
结果看起来像您的输出我同意@Lucent Fox的观点,a在这里非常方便。但是,如果您请求的范围不能超过5½年,则无需创建。称为系统表,或者更准确地说,称为其子集(其中类型为“P”)的系统表可以用作查询中的数字表:
WITH datelist AS (
SELECT
Date = DATEADD(DAY, number, @StartDate)
FROM master..spt_values
WHERE type = 'P'
AND number BETWEEN 0 AND DATEDIFF(DAY, @StartDate, @EndDate)
)
SELECT
Timestamp = d.Date + s.SlotTime
FROM datelist d
INNER JOIN SlotTable s ON s.WeekDay = DATEPART(WEEKDAY, d.Date)
ORDER BY Timestamp
什么定义了1是什么?星期天,星期一,星期四?对不起,是星期一的。SET DATEFIRST 1 SET DATEFORMAT ymdI现在无法思考字符串,所以如果到那时还没有人给出答案,我会在明天留下答案。如果您想亲自尝试,则需要使用DATEPARTdw。我不认为它会像你想的那么复杂。嗨,朗讯,thx的查询,它解释了我很多!看起来确实是一个很有希望的解决方案;我会测试它,让你知道,THX很多!!我不能马上选择答案。30分钟决定最好的sql是不公平的。让它啜饮半天。然后返回并选择最佳解决方案。您可能不应该使用时间类型,因为它是在SQL Server 2008中引入的,OP使用SQL Server 2005。@t-clausen,对于时间值“13:00”,结果是“date 12:59:59.997”,而不是“date 13:00:00”Andriy-看起来他可以使用它。是的,我刚从varchar转换成datetime,没关系。2005年没有时间数据类型没有问题@t-clausen,我选择你的解决方案是因为它速度快,而且不需要额外的表格。非常适合我的场景:谢谢大家的快速回答!我真的很感激!