Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sql-server-2005/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server T-SQL任务-查找两个日期范围内具有指定工作日的所有日期_Sql Server_Sql Server 2005_Tsql - Fatal编程技术网

Sql server T-SQL任务-查找两个日期范围内具有指定工作日的所有日期

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'

在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'
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,我选择你的解决方案是因为它速度快,而且不需要额外的表格。非常适合我的场景:谢谢大家的快速回答!我真的很感激!