选择日期+3天,不包括周末和节假日
Posted
技术标签:
【中文标题】选择日期+3天,不包括周末和节假日【英文标题】:Select date + 3 days, not including weekends and holidays 【发布时间】:2013-05-28 18:59:43 【问题描述】:我已经找到了许多关于在 SQL 中进行日期差异问题的答案,不包括周末和节假日。我的问题是我需要进行日期比较 - 有多少子记录的工作日期在父记录发送日期的三天内?
大多数日期差异答案都涉及日历表,我认为如果我可以构建一个返回 date+3 的子选择,我就可以解决剩下的问题。但我不知道如何返回日期+3。
所以:
CREATE TABLE calendar
(
thedate DATETIME NOT NULL,
isweekday SMALLINT NULL,
isholiday SMALLINT NULL
);
还有:
SELECT thedate AS fromdate, xxx AS todate
FROM calendar
我想要的 todate 是 fromdate + 72 小时,不包括周末和节假日。在 isweekday 而不是 isholiday 的情况下执行 COUNT(*) 很简单,但执行 DATEADD() 是另一回事。
我不知道从哪里开始。
【问题讨论】:
等等...“我想如果我可以构建一个返回日期+3 的子选择,我就可以解决剩下的问题”——当然。完成所有工作后,您就可以解决剩下的问题了。 :) 您还没有将原始问题简化为更简单的问题,您尝试的简化同样复杂。 【参考方案1】:编辑: 更改为将非工作日包含为有效的 fromDates。
WITH rankedDates AS
(
SELECT
thedate
, ROW_NUMBER()
OVER(
ORDER BY thedate
) dateRank
FROM
calendar c
WHERE
c.isweekday = 1
AND
c.isholiday = 0
)
SELECT
c1.fromdate
, rd2.thedate todate
FROM
(
SELECT
c.thedate fromDate
,
(
SELECT
TOP 1 daterank
FROM
rankedDates rd
WHERE
rd.thedate <= c.thedate
ORDER BY
thedate DESC
) dateRank
FROM
calendar c
) c1
LEFT JOIN
rankedDates rd2
ON
c1.dateRank + 3 = rd2.dateRank
您可以在日历表上放置一个日期排名列以简化此操作并避免 CTE:
CREATE TABLE
calendar
(
TheDate DATETIME PRIMARY KEY
, isweekday BIT NOT NULL
, isHoliday BIT NOT NULL DEFAULT 0
, dateRank INT NOT NULL
);
然后您将仅在非节假日工作日设置 daterank 列。
【讨论】:
这几乎行得通。但是因为您是从rankedDates 中提取fromDate,所以它不会返回周末和节假日的值。 哦,所以假期和周末需要 'todate' 值,但需要将 'fromdate' 限制为非假期工作日? 是的。考虑一下,如果我将它添加到表中,而不是使用 CFE,我可以在设置 dateRank 列的脚本中执行此操作。【参考方案2】:这应该可以解决问题,将“顶部”中的数字更改为您想要包含的天数。
declare @date as datetime
set @date = '5/23/13'
select
max(_businessDates.thedate)
from (
select
top 3 _Calendar.thedate
from calendar _Calendar
where _Calendar.isWeekday = 1
and _Calendar.isholiday = 0
and _Calendar.thedate >= @date
order by
_Calendar.thedate
) as _businessDates
对于可以前进或后退一定天数的动态版本,请尝试以下操作:
declare @date as datetime
declare @DayOffset as int
set @date = '5/28/13'
set @DayOffset = -3
select
(case when @DayOffset >= 0 then
max(_businessDates.thedate)
else
min(_businessDates.thedate)
end)
from (
select
top (abs(@DayOffset) + (case when @DayOffset >= 0 then 1 else 0 end)) _Calendar.thedate
from calendar _Calendar
where _Calendar.isWeekday = 1
and _Calendar.isholiday = 0
and ( (@DayOffset >= 0 and _Calendar.thedate >= @date)
or (@DayOffset < 0 and _Calendar.thedate < @date) )
order by
cast(_Calendar.thedate as int) * (case when @DayOffset >=0 then 1 else -1 end)
) as _businessDates
您可以将@DayOffset 设置为正数或负数。
【讨论】:
这是一个独立的查询。但我需要将其用作连接到另一个表的子选择,其中@date 是另一个表中的一个字段。我不能,AIUI,在子选择的上下文中使用字段引用。 我将其创建为我在选择列表中调用的函数。select *, (select [dbo].[FunctionName]('myTable.thedate',3)) as offsetDate from myTable
添加了一个可以使用 dateadd 加入查询的新答案。【参考方案3】:
你只需要 DATEADD,除非我不理解你的问题。
DATEADD(DAY,3,fromdate)
编辑:我知道,不包括周末或节假日,将立即更新。
更新:看起来 Jason 搞定了,但如果您使用 SQL2012 的机会不大,这里是简单版本:
SELECT todate = thedate
fromdate = LEAD(thedate,3) OVER (ORDER BY thedate)
FROM calendar
WHERE isweekday = 1
AND isHoliday = 0
【讨论】:
是的,我也是这么想的,这个问题的措辞有点混乱。 :) 我想增加三天,不包括节假日和周末。也就是说,thedate + 需要多少天才能获得 isholiday 为 0 且 isweekday 为 1 的三天。【参考方案4】:如果您需要它作为 dateAdd 查询,请尝试此操作:
SELECT
allDates.thedate fromDate
,min(nonWeekendHoliday.thedate) toDate
FROM (
SELECT
thedate
FROM
calendar _calendar
) allDates
LEFT JOIN (
SELECT
thedate
FROM
calendar _calendar
WHERE
_calendar.isweekday = 1
AND
_calendar.isholiday = 0
) nonWeekendHoliday
on dateadd(d,3,allDates.thedate) <= nonWeekendHoliday.thedate
where allDates.thedate between '5/20/13' and '5/31/13'
group by
allDates.thedate
【讨论】:
以上是关于选择日期+3天,不包括周末和节假日的主要内容,如果未能解决你的问题,请参考以下文章