我甚至不知道如何开始解决这个问题,我们将不胜感激任何帮助:
我的目标是生成一个表(动态)返回正在工作班次的日期。
设定:
例如: 模式日:7 开课日期:01/01/2015 模式结束日期:2015年12月31日
ID StartshiftDate EndShiftDate OnDuty
-------------------------------------------------------------
1 01/01/2015 01/07/2015 On Duty
2 01/08/2015 01/14/2015 Off Duty
3 01/15/2015 01/21/2015 On Duty
我知道我需要创建从开始日期开始的CTE,我需要为每个日期添加7天。 但我不知道如何确定日期范围是值班还是下班。
我如何创建用于创建行的循环直到模式结束日期?
任何帮助将不胜感激
答案 0 :(得分:3)
正如您所提到的,您需要使用Recursive CTE
。试试这个。
DECLARE @Startdate DATE= '01/01/2015',
@enddate DATE = '01/31/2015',
@Patterndays INT=7;
WITH cte
AS (SELECT CONVERT(DATE, @Startdate) [dates],
1 AS id,
CONVERT(VARCHAR(20), 'On Duty') AS duty
UNION ALL
SELECT Dateadd(dd, @Patterndays, [dates]),
ID + 1,
CASE
WHEN ( id + 1 ) % 2 = 1 THEN CONVERT(VARCHAR(20), 'On Duty')
ELSE CONVERT(VARCHAR(20), 'Off Duty')
END
FROM cte
WHERE dates < Dateadd(dd, -@Patterndays, CONVERT(DATE, @enddate)))
SELECT id,
dates AS StartshiftDate,
Dateadd(DD, 6, dates)EndShiftDate,
duty
FROM cte
Option (maxrecursion 0)
结果:
id StartshiftDate EndShiftDate duty
-- -------------- ------------ -------
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
答案 1 :(得分:1)
我会使用一个数字表。
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
答案 2 :(得分:0)
我解决了这个问题
DECLARE @StartDate DATETIME = '2015-01-01'
DECLARE @EndDate DATETIME = '2015-01-31'
DECLARE @Pattern INT = 14
;WITH
N0 AS (SELECT 1 AS n UNION ALL SELECT 7)
,N1 AS (SELECT 1 AS n FROM N0 t1, N0 t2)
,N2 AS (SELECT 1 AS n FROM N1 t1, N1 t2)
,N3 AS (SELECT 1 AS n FROM N2 t1, N2 t2)
,N4 AS (SELECT 1 AS n FROM N3 t1, N3 t2)
,N5 AS (SELECT 1 AS n FROM N4 t1, N4 t2)
,N6 AS (SELECT 1 AS n FROM N5 t1, N5 t2)
,nums AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS num FROM N6),
ShiftPattern AS (
select
ROW_NUMBER() OVER(ORDER BY num ASC) as ID,
(ROW_NUMBER() OVER(ORDER BY num ASC) % 2) as d,
DATEADD(day, -(@Pattern-1), DATEADD(day, num-1, @StartDate)) as Start,
DATEADD(day, num-1, @StartDate) AS Enddate,
CASE
WHEN (ROW_NUMBER() OVER(ORDER BY num ASC) % 2) = 1 THEN 'On Duty'
WHEN (ROW_NUMBER() OVER(ORDER BY num ASC) % 2) = 0 THEN 'Off Duty'
END AS 'Duty'
FROM nums
WHERE
(num % @Pattern) = 0
AND num <= DATEDIFF(day, @StartDate, @EndDate) + 1)
SELECT *
FROM ShiftPattern