计算工作日 - 星期一到星期五在Sql

时间:2011-07-25 17:51:19

标签: tsql sql-server-2008

我如何计算星期一到星期五的最后工作五天。我当前的脚本获取了最后一个星期一的日期,但我无法获得上周五的日期。请帮忙

declare @StartDate datetime
declare @EndDate datetime


--Calculate date range for report

select @EndDate = Cast(convert(char(10), getdate(), 101)+' 00:00:00' as datetime)
select @StartDate = DateAdd(d, -7, @EndDate)
select @EndDate = Cast(convert(char(10), getdate(), 101)+' 23:59:59' as datetime)

select @StartDate startdate
select @EndDate  enddate

6 个答案:

答案 0 :(得分:2)

Datepart为您提供了一个简单的方法来获取工作日:

 SET DATEFIRST 1  -- monday is first day of the week
 SELECT DATEPART(weekday, '20110725')
 -- result is 1

有关详细信息,请参阅T-SQL Date functionsSET DATEFIRST

使用工作日,你可以计算出上周一和周五的前几天并使用'AddDate'(就像你现在正在做的那样)来计算它们。

请注意,您应该真正使用DATEDIFF进行此类日期范围选择。如果您在23:59:59之间选择所有内容,则总会有一些记录被遗漏。例如23:59:59.001超出范围,但它仍然在同一天。使用DATEDIFF,您可以测试它是否在同一天,丢弃时间部分。无需费心去铸造字符串,增加时间和退回。

答案 1 :(得分:1)

答案比人们假设的要复杂得多。你需要的是回到5天前找到那之前的第一个星期一,以及之后的第一个星期五。您可以使用@@ datefirst,计算或'设置firstdate 1'。我不喜欢使用最后一个,因为它不能在函数中完成。正如您所看到的,我使用了计算,@@ datefirst也一样好。

假设你想要过去星期五的最后一组星期一。这个查询就可以了。如果您信任当前的星期一,您可以添加5天并减去1分钟(我不相信它,如果您在星期一运行查询,它只返回上一个星期一)。

在我的SQL中,我的目标不是简单,我的目的是为了有效。

DECLARE @getdate datetime = dateadd(day, cast(getdate() as int), 0)
-- the 'Declare' can also be written like this thanks to @Andriy M
--DECLARE @getdate = CAST(GETDATE() - 0.5 AS int)
SELECT @getdate - 5 - CAST(@getdate- 5 as int) % 7 monday,
dateadd(minute, -1, @getdate) - CAST(@getdate- 5 as int) % 7 friday

结果:

Monday              Friday
2011-07-18 0:00:00  2011-07-22 23:59:00

*第一个解决方案是休息一天@AndriyM指出,它已经解决了。


回答@Andriy M

出于某种原因,它的行为与我的预期不同。我无法解释,但试试这个

select cast(dateadd(day, cast(getdate() as int) - .5, 0) as datetime),
cast(dateadd(day, cast(getdate() as int), 0) as datetime),
cast(dateadd(day, cast(getdate() as int) + .5, 0) as datetime)

在早上最后2个字段具有相同的值,在晚上前2个字段具有相同的值。我和你一样惊讶,我希望我能解释一下。它在这里测试过 http://data.stackexchange.com/stackoverflow/query/new

答案 2 :(得分:0)

这两个问题:

可能会有所帮助。

虽然,如果你已经知道如何找到上周一,你可以使用DATEADD()函数在周一日期添加4天,轻松找到相应的星期五。例如:

SELECT @EndDate = DATEADD(DAY, 4, @StartDate)

答案 3 :(得分:0)

这都与TODAY的约会有关,对吗?

因此,找出今天的内容DATEPART(weekday, getdate())

然后将其转换为调整变量 - 例如:

declare @adjustment int
set @adjustment = CASE DATEPART(weekday, getdate()) WHEN 'MONDAY' THEN 0 WHEN 'TUESDAY' THEN 1, ...END

那么你想要的星期一就是今天 - 7 - @adjustment
...而你想要的星期五是星期一+ 5

Declare @myMonday smalldatetime,
        @myFriday smalldatetime
set @myMonday = getdate() - 7 - @adjustment
set @myFriday = @myMonday + 5

答案 4 :(得分:0)

DECLARE @my int
DECLARE @myDeduct int
DECLARE @day INT
DECLARE @mydate DATETIME

SET @mydate = '2012-08-01'

SET @myDeduct = 0
SET DateFirst 1 -- Set it monday=1 (value)

--Saturday and Sunday on the first and last day of a month will Deduct 1
IF (DATEPART(weekday,(DATEADD(dd,-(DAY(@mydate)-1),@mydate))) > 5)
SET @myDeduct = @myDeduct + 1

IF (DATEPART(weekday,(DATEADD(dd,-(DAY(DATEADD(mm,1,@mydate))),DATEADD(mm,1,@mydate)))) > 5)
SET @myDeduct = @myDeduct + 1

SET @my = day(DATEADD(dd,-(DAY(DATEADD(mm,1,@mydate))),DATEADD(mm,1,@mydate)))

select (((@my/7) * 5 + (@my%7)) - @myDeduct) as Working_Day_per_month

答案 5 :(得分:0)

我也会戴上帽子。 : - )

DECLARE @Date      datetime = '01/11/2015'
DECLARE @StartDate datetime = DATEADD(d, (1 - (DATEDIFF(d, CAST('1899.12.31' AS datetime), @Date - 6) % 7)), @Date - 6) -- MONDAY
DECLARE @EndDate   datetime = DATEADD(d, (5 - (DATEDIFF(d, CAST('1899.12.31' AS datetime), @Date - 6) % 7)), @Date - 6) -- FRIDAY

      SELECT '@Date'      as Variable ,CONVERT(date, @Date)      as DateValue ,DATENAME(dw, @Date)      as DayOfTheWeek
UNION SELECT '@StartDate' as Variable ,CONVERT(date, @StartDate) as DateValue ,DATENAME(dw, @StartDate) as DayOfTheWeek
UNION SELECT '@EndDate'   as Variable ,CONVERT(date, @EndDate)   as DateValue ,DATENAME(dw, @EndDate)   as DayOfTheWeek

-- Variable    DateValue   DayOfTheWeek
-- ----------  ----------  ------------
-- @Date       2015-01-11  Sunday
-- @StartDate  2015-01-05  Monday
-- @EndDate    2015-01-09  Friday

BONUS:在这里,您可以使用相同的技术生成5个工作日的快速表格。

SELECT DATENAME(dw, DATEADD(d, TT.DaysToAdd, DATEADD(d, (1 - (DATEDIFF(d, CAST('1899.12.31' AS datetime), @Date - 6) % 7)), @Date - 6))) as DayOfTheWeek
      ,             DATEADD(d, TT.DaysToAdd, DATEADD(d, (1 - (DATEDIFF(d, CAST('1899.12.31' AS datetime), @Date - 6) % 7)), @Date - 6))  as DateValue
  FROM (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) - 1 as DaysToAdd FROM (VALUES(0),(0),(0),(0),(0)) a(n)) as TT

-- DayOfTheWeek                   DateValue
-- ------------------------------ -----------------------
-- Monday                         2015-01-05 00:00:00.000
-- Tuesday                        2015-01-06 00:00:00.000
-- Wednesday                      2015-01-07 00:00:00.000
-- Thursday                       2015-01-08 00:00:00.000
-- Friday                         2015-01-09 00:00:00.000

以下是解释:

1)首先,我们需要知道开始评估的日期。在本例中,我们选择使用2015年1月11日星期日。

DECLARE @Date2 datetime = '01/11/2015'

1b)这是一个很好的获得星期几的名字的奖励技术,给定日期值

SELECT @Date2 as DateValue, DATENAME(dw, @Date2) as DayOfTheWeek

2)接下来,我们需要确定性地(根据美国日历)知道一周中给定的一天在数字上是1到7之间

  • 注意:1899.12.31是1900.01.01之前的第一个星期日,它是SmallDateTime数据类型的MINIMUM值。
  • 注意:是的,您可以更简单地使用DATEPART(dw,@ Date),但鉴于某些服务器环境可能具有不同的配置,它不具有确定性
  • 结果:1​​ =星期天| 2 =星期一| 3 =星期二| 4 =星期三| 5 =周四| 6 =星期五| 7 =星期六

    SELECT ((DATEDIFF(d, CAST('1899.12.31' AS datetime), @Date2) % 7) + 1) [DayOfWeek Deterministic (Based on US)]
    

3)现在,给定任何日期,你应该有一个确定的方法来确定给定周的星期一

SELECT DATEADD(d, (1 - (DATEDIFF(d, CAST('1899.12.31' AS datetime), @Date2) % 7)), @Date2) as [Monday Day of the Week - Deterministic (Based on US)]

4)现在,给定任何日期,你应该有一个确定的方法来确定给定周的星期五

SELECT DATEADD(d, (5 - (DATEDIFF(d, CAST('1899.12.31' AS datetime), @Date2) % 7)), @Date2) as [Monday Day of the Week - Deterministic (Based on US)]

5)我们需要的最后一个日期操作技术是知道如何进入一个工作日的第一个完整周发生的一周。例如,如果我们在星期天,我们从它减去1天,那么我们到星期六,这使我们在前一周,这是工作日的第一个完整周。或者,如果我们也从星期一减去1天,它只会让我们到星期日,这不是前一周,所以减去1天是不够的。另一方面,如果我们在星期六和减去7天,我们将超过工作日的前一整周,进入它前一周,这太过分了。这是分析的一个缺点,以确定你可以减去的神奇数字是什么,它将适用于一周中的任何一天。如下所示,幻数为6。

--                                            DAYS TO SUBTRACT
-- Day of the Week      - 0     - 1     - 2     - 3     - 4     - 5     - 6     - 7
-- ===============      ====    ====    ====    ====    ====    ====    ====    ====
-- Sunday               Bad     Good    Good    Good    Good    Good    Good    Good
-- Monday               Bad     Bad     Good    Good    Good    Good    Good    Good
-- Tuesday              Bad     Bad     Bad     Good    Good    Good    Good    Good
-- Wednesday            Bad     Bad     Bad     Bad     Good    Good    Good    Good
-- Thursday             Bad     Bad     Bad     Bad     Bad     Good    Good    Good
-- Friday               Bad     Bad     Bad     Bad     Bad     Bad     Good    Good
-- Saturday             Good    Good    Good    Good    Good    Good    Good    Bad

奖金)如果你想把所有工作日都放在小桌子上,那么你也想要使用基于零的快速“计数表”。有很多方法可以做到这一点,所以选择你的味道。这里很少。

SELECT * FROM (SELECT 0 as DaysToAdd UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4) as TT
SELECT * FROM (SELECT TOP 5 ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) - 1 as DaysToAdd FROM sys.all_columns a CROSS JOIN sys.all_columns b) as TT
SELECT * FROM (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) - 1 as DaysToAdd FROM (VALUES(0),(0),(0),(0),(0)) a(n)) as TT