在T-SQL(MSSQL 2005)中,我的任务非常艰巨。我有一张这样的桌子:
WeekDay| SlotTime
------------------
| 1 | 07:00
| 3 | 09:00
| 7 | 14:00
| 1 | 15:00
| 4 | 22:00
| 6 | 08:00
其中第一列是WeekDay号,第二列是一些Time值。
作为查询的参数,我有2个日期,例如:
StartDate = '2011-07-20'
EndDate = '2011-08-17'
这是我的数据的范围定义。我必须为这些范围生成所有日期,其中WeekDay(来自上表)发生并添加到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
答案 0 :(得分:1)
您可以使用所谓的数字表。只需创建一个包含任意数量的行的表,就像日期之间的天数一样,按顺序编号。
这是在SQL 2008中创建数字表的一种非常流畅的方式,也可能在2005年工作: http://archive.msdn.microsoft.com/SQLExamples/Wiki/View.aspx?title=NumbersTable
或者,您只需创建一个带有标识的表,然后将TOP 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
答案 1 :(得分:1)
这样就可以了解
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)
(结果看起来像你的输出)
答案 2 :(得分:0)
我同意@Lucent Fox的观点,number table在这里非常方便。但是,如果您请求的范围永远不会超过5年半,则无需创建它。名为master..spt_values
的系统表,或者更确切地说,其type = '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