【问题标题】:TSQL datediff only business hoursTSQL datediff 仅营业时间
【发布时间】:2015-01-14 14:44:49
【问题描述】:

在一个视图中,这两个日期来自一个表:

2014-12-17 14:01:03.523 - 2014-12-20 09:59:28.783

假设我可以计算一天中从早上 8 点到下午 5 点的小时数,我需要知道日期差异(以小时为单位)。

当然不能包括周六和周日。

我尝试在选择中使用此代码,但我只得到了几天的差异,不包括周六和周日。

(DATEDIFF(HOUR, convert(datetime,t.EXT_DATAINS-2), convert(datetime,b.EXT_DATAINS-2)) + 1) 
  -(DATEDIFF(wk, convert(datetime,t.EXT_DATAINS-2), convert(datetime,b.EXT_DATAINS-2)) * 2)
  -(CASE WHEN DATENAME(dw, convert(datetime,t.EXT_DATAINS-2)) = 'Sunday' THEN 1 ELSE 0 END)
  -(CASE WHEN DATENAME(dw, convert(datetime,b.EXT_DATAINS-2)) = 'Saturday' THEN 1 ELSE 0 END) differenza

例子:

2014-12-17 : 3hrs
2014-12-18 : 8hrs
2014-12-19 : 8hrs
2014-12-20 : 2hrs 
Tot        : 21hrs

【问题讨论】:

  • 没有标准函数可以帮助您做到这一点。除了定义您的“营业时间”(午餐时间计算吗?)和假期安排之外,您还必须定义当范围在营业时间之外开始或结束时会发生什么。例如:如果从下午 3 点到下午 6 点,那是多少小时?凌晨 3 点到晚上 10 点怎么样?
  • 这两个日期之间的差异导致您想要什么?
  • 你能告诉我们你尝试了什么,例如用于从开始日期到结束日期运行的 CTE 或数字表,CASE 用于确定每个日期包含的小时数,SUM 用于最终结果?
  • 这两个日期 2014-12-17 14:01:03.523 - 2014-12-20 09:59:28.783 会有什么区别

标签: sql-server tsql time datediff


【解决方案1】:

使用Recursive CTE 获取所有带日期的小时。

方法 1:获取 FromDate 和 ToDate 之间的所有日期

DECLARE @FROMDATE DATETIME='2014-12-17 14:01:03.523'
DECLARE @TODATE DATETIME='2014-12-20 09:59:28.783'

;WITH CTE AS
(
   SELECT @FROMDATE FROMDATE
   UNION ALL
   SELECT DATEADD(HH,1,FROMDATE)
   FROM CTE
   WHERE FROMDATE<@TODATE 
)
SELECT ISNULL(CAST(CAST(FROMDATE AS DATE)AS VARCHAR(12)),'Tot')FROMDATE,
CAST(COUNT(FROMDATE)AS VARCHAR(4))+'hrs' [HOURS] 
FROM CTE
WHERE DATEPART(HH,FROMDATE) BETWEEN 9 AND 16
AND DATENAME(DW,FROMDATE)<>'SATURDAY' AND DATENAME(DW,FROMDATE)<>'SUNDAY'
GROUP BY CAST(FROMDATE AS DATE)
WITH ROLLUP

方法 2:获取 FromDate 和 ToDate 之间缺失的日期,其中 8 硬编码为 Hrs

这种方法将更易于实施 - 性能调整

DECLARE @FROMDATE DATETIME='2014-12-17 14:01:03.523'
DECLARE @TODATE DATETIME='2014-12-20 09:59:28.783'

;WITH CTE AS
(
   -- Get missing dates between FromDate and ToDate
   SELECT  DATEADD(DAY,1,@FROMDATE) FROMDATE,8 HRS
   UNION ALL
   SELECT DATEADD(DAY,1,FROMDATE),8
   FROM CTE
   WHERE FROMDATE < DATEADD(DAY,-1,@TODATE) 
)
,CTE2 AS
(
   -- Gets the Hours for FromDate
   SELECT CAST(@FROMDATE AS DATE) DATES, CAST(CAST(DATEDIFF
   (
      MINUTE,@FROMDATE,CAST(CAST(CAST(@FROMDATE AS DATE) AS VARCHAR(12))+' 17:00:00' AS DATETIME)
   )AS NUMERIC(18,2))/60 AS DECIMAL(18,0)) HRS
   WHERE DATENAME(DW,@FROMDATE)<>'SATURDAY' AND DATENAME(DW,@FROMDATE)<>'SUNDAY'

   UNION ALL

   -- Select Hours in between dates
   SELECT CAST(FROMDATE AS DATE) NEWDATE,HRS
   FROM CTE
   WHERE DATENAME(DW,FROMDATE)<>'SATURDAY' AND DATENAME(DW,FROMDATE)<>'SUNDAY'

   UNION ALL

   -- Select Hours for ToDate
   SELECT CAST(@TODATE AS DATE), CAST(CAST(DATEDIFF
   (
      MINUTE,CAST(CAST(CAST(@TODATE AS DATE) AS VARCHAR(12))+' 08:00:00' AS DATETIME),@TODATE
   )AS NUMERIC(18,2))/60 AS DECIMAL(18,0))
   WHERE DATENAME(DW,@TODATE)<>'SATURDAY' AND DATENAME(DW,@TODATE)<>'SUNDAY'
)
-- Use ROLLUP to find the sum of Hours and show it in last row
SELECT ISNULL(CAST(DATES AS VARCHAR(20)),'Tot')DATES,
CAST(SUM(HRS)AS VARCHAR(4))+'hrs' HRS
FROM CTE2
GROUP BY DATES
WITH ROLLUP

【讨论】:

    【解决方案2】:

    @marco burrometo

    创建一个静态表,该表将具有所有日历功能,例如假期功能,周六和周日是假期。对你有很大帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-21
      • 2015-04-11
      • 2014-05-31
      • 2011-02-12
      • 1970-01-01
      相关资源
      最近更新 更多