sql通过开放和关闭小时范围计算工作日的营业时间

时间:2014-03-19 13:28:58

标签: sql sql-server date

我想计算给定日期范围(开放日和结束日)之间的营业时间

例如:营业时间

  

ID WeekName OpeningHour ClosingHour

     

01 Monday 8.00AM 4.00PM

     

02 Tuesday 8.00AM 4.00PM

     

03 Wednesday 8.00AM 4.00PM

     

04 Thursday 8.00AM 4.00PM

     

05 Friday 8.00AM 4.00PM

如果我给出例如日期范围 开放日:01/04/2014 09.00AM
闭幕日:03/04/2014 14.00 AM

我想从给定的日期范围计算营业时间 给定范围之间有3天

01/04/2014

02/04/2014

03/04/2014

首先,我想查看日期名称并计算营业时间(从上表开始)的小时数。

01/04/2014 - 星期二

02/04/2014 - 周三

03/04/2014 - 周四

我期待的结果:

  

GivenDate DayID DayName DateDiff

     

01/04/2014 01 Tuesday 7

     

02/04/2014 02 Wednesday 8

     

03/04/2014 03 Thursday 6

2 个答案:

答案 0 :(得分:1)

在Stackoverflow上,通常不赞成问一个问题,期待别人为你做你的工作。您至少应该显示一些最小的努力,例如到目前为止您尝试过的一些SQL。

那就是说,这里的查询会返回你想要的内容。即使您没有日期(日历)表,此查询仍然有效,因为它会从系统表生成一系列数字。然后,这些数字又被添加到开始日期,以便在该区间内每天返回一条记录:

SELECT * INTO #WorkingHours 
FROM (VALUES (1, 'Monday', '08:00', '16:00')
    ,(2, 'Tuesday', '08:00', '16:00')
    ,(3, 'Wednesday', '08:00', '16:00')
    ,(4, 'Thursday', '08:00', '16:00')
    ,(5, 'Friday', '08:00', '16:00'))
E(DayId, DayName, OpeningHour, ClosingHour)

DECLARE @StartDate DATETIME = '2014-04-01 09:00:00'
DECLARE @EndDate DATETIME = '2014-04-03 14:00:00'

SELECT [GivenDate], [DayID], [DayName],
    DATEDIFF(HOUR, CASE WHEN @StartDate > [OpeningDateTime] THEN @StartDate ELSE [OpeningDateTime] END, 
        CASE WHEN @EndDate < [ClosingDateTime] THEN @EndDate ELSE [ClosingDateTime] END) AS [DateDiff]
FROM (
    SELECT CAST(@StartDate + n - 1 AS DATE) AS [GivenDate]
        , n AS [DayID]
        , DATENAME(dw, @StartDate + n - 1) AS [DayName]
        , CAST(CAST(CAST(@StartDate + n - 1 AS DATE) AS VARCHAR) + ' ' + OpeningHour AS DateTime) AS OpeningDateTime
        , CAST(CAST(CAST(@StartDate + n - 1 AS DATE) AS VARCHAR) + ' ' + ClosingHour AS DateTime) AS ClosingDateTime
    FROM    
        -- Numbers, for expanding the date range:
        (SELECT ROW_NUMBER() OVER (ORDER BY object_id) n FROM sys.all_objects) Numbers
    INNER JOIN #WorkingHours ON DayName = DATENAME(dw, @StartDate + n - 1)
    WHERE Numbers.n <= DATEDIFF(d, @StartDate, @EndDate) + 1
) SubQuery

以下是结果输出:

enter image description here

答案 1 :(得分:0)

如果您有日期(日历)表,这非常简单。首先,您将开始日期和结束日期加入日历表以获取日期。比你只需将DATENAME与你桌上的内容进行比较。下面是使用表变量和DATE(日历)表的示例代码。

DECLARE @BusHours TABLE
    (
     ID INT
    ,DayOfWeekName VARCHAR(10)
    ,OpeningHour VARCHAR(7)
    ,ClosingHOur VARCHAR(7)
    )

INSERT INTO @BusHours
        ( ID, DayOfWeekName, OpeningHour, ClosingHour )
    VALUES  ( 1, 'Monday', '08:00AM', '04:00PM' )
    ,       ( 2, 'Tuesday', '08:00AM', '04:00PM' )
    ,       ( 3, 'Wednesday', '08:00AM', '04:00PM' )
    ,       ( 4, 'Thursday', '08:00AM', '04:00PM' )
    ,       ( 5, 'Friday', '08:00AM', '04:00PM' )

DECLARE @StartDate DATETIME = '04/01/2014 09:00AM'
   ,@EndDate DATETIME = '04/03/2014 14:00PM'

SELECT d.Date_Dt AS GivenDate
       ,b.ID AS DayID
       ,b.DayOfWeekName AS DayName
       ,CASE WHEN DATENAME(WEEKDAY, @StartDate) = b.DayOfWeekName
             THEN DATEDIFF(hh, @StartDate,
                           CONVERT(DATETIME, CONVERT(VARCHAR(12), @StartDate, 101) + ' ' + b.ClosingHour))
             WHEN DATENAME(WEEKDAY, @EndDate) = b.DayOfWeekName
             THEN DATEDIFF(hh, CONVERT(DATETIME, CONVERT(VARCHAR(12), @EndDate, 101) + ' ' + b.OpeningHour), @EndDate)
             ELSE DATEDIFF(hh, CONVERT(DATETIME, '01/01/2014' + ' ' + b.OpeningHour),
                           CONVERT(DATETIME, '01/01/2014' + ' ' + b.ClosingHour))
        END AS HoursOperation
    FROM dbo.Date AS d
    JOIN @BusHours AS b
        ON DATENAME(WEEKDAY, d.Date_Dt) = b.DayOfWeekName
    WHERE d.Date_Dt >= CONVERT(DATE, @startDate)
        AND d.Date_Dt <= CONVERT(DATE, @EndDate)

我工作中[Date]表的表定义。不是每个人都有相同的实现,但如果你四处搜索,你可以找到许多脚本来生成它。

CREATE TABLE [dbo].[Date]
    (
     [Date_Id] [int] NOT NULL
    ,[Date_Dt] [date] NULL
    ,[Date_Nm] [varchar](9) NULL
    ,[DayType_Cd] [varchar](7) NULL
    ,[DayofWeek_Nbr] [int] NULL
    ,[DayofWeek_Nm] [varchar](10) NULL
    ,[DayofMonth_Nbr] [int] NULL
    ,[DayofYear_Nbr] [int] NULL
    ,[Week_Nbr] [int] NULL
    ,[Week_Nm] [varchar](5) NULL
    ,[WeekFirstDay_Dt] [date] NULL
    ,[WeekLastDay_Dt] [date] NULL
    ,[WeekofYear_Nbr] [int] NULL
    ,[Month_Nbr] [int] NULL
    ,[Month_6_Nbr] [int] NULL
    ,[Month_Nm] [varchar](6) NULL
    ,[MonthFull_Nm] [varchar](9) NULL
    ,[MonthLastDay_Dt] [date] NULL
    ,[MonthofYear_Nbr] [int] NULL
    ,[Quarter_Nbr] [int] NULL
    ,[Quarter_Nm] [varchar](5) NULL
    ,[QuarterofYear_Nbr] [int] NULL
    ,[Year_Nbr] [int] NULL
    ,[Year_Nm] [varchar](4) NULL
    ,[FYDayofWeek_Nbr] [int] NULL
    ,[FYWeek_Nbr] [int] NULL
    ,[FYWeek_Nm] [varchar](5) NULL
    ,[FYWeekFirstDay_Dt] [date] NULL
    ,[FYWeekLastDay_Dt] [date] NULL
    ,[FYWeekofYear_Nbr] [int] NULL
    )