我会使用一个数字表。
http://web.archive.org/web/20150411042510/http://sqlserver2000.databases.aspfaq.com/why-should-i-consider-using-an-auxiliary-numbers-table.html
http://sqlperformance.com/2013/01/t-sql-queries/generate-a-set-1
This article 比较了不同的生成方式,包括递归 CTE,它比其他方式慢得多。
如何生成数字表并不重要,因为通常只生成一次。对于这个例子,我将使用上面文章中的一种方法填充一个包含 10000 个数字的表变量。
declare @TNumbers table (Number int);
INSERT INTO @TNumbers (Number)
SELECT TOP (10000) ROW_NUMBER() OVER (ORDER BY s1.[object_id])
FROM sys.all_objects AS s1 CROSS JOIN sys.all_objects AS s2
OPTION (MAXDOP 1);
现在我们有一个数字表,生成您的日期是一个简单的公式:
DECLARE @VarStartDate date = '2015-01-01';
DECLARE @VarEndDate date = '2015-12-31';
DECLARE @VarShiftLength int = 7;
SELECT
N.Number AS ID
, DATEADD(day, (N.Number - 1) * @VarShiftLength, @VarStartDate) AS StartShiftDay
, DATEADD(day, N.Number * @VarShiftLength - 1, @VarStartDate) AS EndShiftDay
, CASE WHEN N.Number % 2 = 0 THEN 'Off Duty' ELSE 'On Duty' END AS OnDuty
FROM
@TNumbers AS N
WHERE
DATEADD(day, N.Number * @VarShiftLength - 1, @VarStartDate) <= @VarEndDate
ORDER BY ID;
结果集:
ID StartShiftDay EndShiftDay OnDuty
1 2015-01-01 2015-01-07 On Duty
2 2015-01-08 2015-01-14 Off Duty
3 2015-01-15 2015-01-21 On Duty
4 2015-01-22 2015-01-28 Off Duty
5 2015-01-29 2015-02-04 On Duty
6 2015-02-05 2015-02-11 Off Duty
7 2015-02-12 2015-02-18 On Duty
8 2015-02-19 2015-02-25 Off Duty
9 2015-02-26 2015-03-04 On Duty
10 2015-03-05 2015-03-11 Off Duty
11 2015-03-12 2015-03-18 On Duty
12 2015-03-19 2015-03-25 Off Duty
13 2015-03-26 2015-04-01 On Duty
14 2015-04-02 2015-04-08 Off Duty
15 2015-04-09 2015-04-15 On Duty
16 2015-04-16 2015-04-22 Off Duty
17 2015-04-23 2015-04-29 On Duty
18 2015-04-30 2015-05-06 Off Duty
19 2015-05-07 2015-05-13 On Duty
20 2015-05-14 2015-05-20 Off Duty
21 2015-05-21 2015-05-27 On Duty
22 2015-05-28 2015-06-03 Off Duty
23 2015-06-04 2015-06-10 On Duty
24 2015-06-11 2015-06-17 Off Duty
25 2015-06-18 2015-06-24 On Duty
26 2015-06-25 2015-07-01 Off Duty
27 2015-07-02 2015-07-08 On Duty
28 2015-07-09 2015-07-15 Off Duty
29 2015-07-16 2015-07-22 On Duty
30 2015-07-23 2015-07-29 Off Duty
31 2015-07-30 2015-08-05 On Duty
32 2015-08-06 2015-08-12 Off Duty
33 2015-08-13 2015-08-19 On Duty
34 2015-08-20 2015-08-26 Off Duty
35 2015-08-27 2015-09-02 On Duty
36 2015-09-03 2015-09-09 Off Duty
37 2015-09-10 2015-09-16 On Duty
38 2015-09-17 2015-09-23 Off Duty
39 2015-09-24 2015-09-30 On Duty
40 2015-10-01 2015-10-07 Off Duty
41 2015-10-08 2015-10-14 On Duty
42 2015-10-15 2015-10-21 Off Duty
43 2015-10-22 2015-10-28 On Duty
44 2015-10-29 2015-11-04 Off Duty
45 2015-11-05 2015-11-11 On Duty
46 2015-11-12 2015-11-18 Off Duty
47 2015-11-19 2015-11-25 On Duty
48 2015-11-26 2015-12-02 Off Duty
49 2015-12-03 2015-12-09 On Duty
50 2015-12-10 2015-12-16 Off Duty
51 2015-12-17 2015-12-23 On Duty
52 2015-12-24 2015-12-30 Off Duty