【问题标题】:Count how many times a time occurs within a date range计算某个时间在某个日期范围内出现的次数
【发布时间】:2017-09-15 09:17:09
【问题描述】:

如果已经有人问过这个问题,我想不出一个好的方法来正确搜索这个问题。

我正在 SQL 2008 R2 中寻找一种方法来计算两个日期时间值之间出现了多少次下午 6 点。

例如在 '2017-04-17 19:00:00''2017-04-19 17:00:00' 6pm 之间仅发生一次虽然时间跨度不同的 3 天。

'2017-04-17 18:00:00''2017-04-19 18:00:00' 之间发生 3 次,同时也跨越3 天。

这是一个非常愚蠢的表达我想要的插图。

timecount(hh, 6, min(datefield), max(datefield))

谢谢

【问题讨论】:

  • 如果你的日期范围很长,比如月份或年份呢?

标签: sql sql-server sql-server-2008 datetime


【解决方案1】:

这里给出任何日期范围之间的计数

declare @time datetime='06:00:00'

declare @startDate datetime='04/20/2017 05:00:00'

declare @enddate datetime='04/21/2017 05:00:00'

SELECT 
  case 
    WHEN datediff(ss,@time, convert(time(0),@startDate)) <=0  and   datediff(ss,@time, convert(time(0),@enddate)) >=0

     THEN datediff(dd,@startDate,@enddate) +1 
WHEN   (datediff(ss,@time, convert(time(0),@startDate)) <=0  and 
datediff(ss,@time, convert(time(0),@enddate)) <=0

        OR
        datediff(ss,@time, convert(time(0),@startDate))> 0  and 

datediff(ss,@time, convert(time(0),@enddate)) >0

        OR

        datediff(ss,@time, convert(time(0),@startDate))> 0  and datediff(ss,@time, convert(time(0),@enddate)) <=0
        )
then  datediff(dd,@startDate,@enddate) 
ELSE  
datediff(dd,@startDate,@enddate)-1
END

【讨论】:

    【解决方案2】:

    这是两个日期时间之间每下午 6 点的计数:

    DECLARE @StartDate datetime
    DECLARE @EndDate datetime
    set @StartDate = '2017-04-17 19:00:00'
    set @EndDate = '2017-04-19 17:00:00'
    
    ;WITH cte1 (S) AS (
    SELECT 1 FROM (VALUES (1), (1), (1), (1), (1), (1), (1), (1), (1), (1)) n (S)
    ),
    cte2 (S) AS (SELECT 1 FROM cte1 AS cte1 CROSS JOIN cte1 AS cte2),
    cte3 (S) AS (SELECT 1 FROM cte1 AS cte1 CROSS JOIN cte2 AS cte2)
    
    select count(datepart(hour,result)) as count from
    (SELECT TOP (DATEDIFF(hour, @StartDate, @EndDate) + 1)
            result = DATEADD(hour, ROW_NUMBER() OVER(ORDER BY S) - 1, @StartDate)
    FROM cte3) as res where datepart(hour,result) = 18
    

    这是两个日期时间之间下午 6 点的详细视图:

    DECLARE @StartDate datetime
    DECLARE @EndDate datetime
    set @StartDate = '2017-04-17 19:00:00'
    set @EndDate = '2017-04-19 17:00:00'
    
    ;WITH cte1 (S) AS (
    SELECT 1 FROM (VALUES (1), (1), (1), (1), (1), (1), (1), (1), (1), (1)) n (S)
    ),
    cte2 (S) AS (SELECT 1 FROM cte1 AS cte1 CROSS JOIN cte1 AS cte2),
    cte3 (S) AS (SELECT 1 FROM cte1 AS cte1 CROSS JOIN cte2 AS cte2)
    
    select result,datepart(hour,result)  from
    (SELECT TOP (DATEDIFF(hour, @StartDate, @EndDate) + 1)
            result = DATEADD(hour, ROW_NUMBER() OVER(ORDER BY S) - 1, @StartDate)
    FROM cte3) as res where datepart(hour,result) = 18
    

    【讨论】:

      【解决方案3】:

      试试下面的脚本,使用CTE

      DECLARE @F_DATE     AS DATETIME =   '2017-04-17 19:00:00'
              ,@T_DATE    AS DATETIME =   '2017-04-19 17:00:00'
      
      
      ;WITH CTE
      AS  (
          SELECT  (CASE WHEN DATEPART(HH,@F_DATE) <= 18
                      THEN @F_DATE 
                      ELSE (CASE WHEN  DATEDIFF(DAY,@F_DATE,@T_DATE) > 0 
                              THEN DATEADD(DAY,1,@F_DATE) END)
                   END)   AS  CDATE
      
          UNION ALL
      
          SELECT  DATEADD(DAY,1,CDATE)
          FROM    CTE
          WHERE   DATEADD(DAY,1,CDATE)    <=  @T_DATE
      )
      
      SELECT COUNT(CDATE) DATE_COUNT 
      FROM CTE
      OPTION ( MAXRECURSION 0 )
      

      【讨论】:

      • CTE 有一些流程:最大递归深度和性能。除非没有其他办法,否则最好避免使用 CTE。
      【解决方案4】:

      试试下面的公式,我尝试过不同的场景,它可以工作,如果我错过任何场景并且不能按照您的要求工作,请告诉我。

      DECLARE @firstDate Datetime='17-Apr-2017 17:00:00'
      DECLARE @secondDate Datetime='17-Apr-2017 18:59:00'
      
      
      SELECT
          CASE WHEN DATEDIFF(day,@firstDate,@secondDate)=0
          THEN IIF(CAST(@firstDate AS TIME) <='18:00' AND DATEPART(hh,@secondDate) >=18,1,0)
          ELSE 
              CASE WHEN 
                  (
                      CAST(@firstDate AS TIME) <='18:00' AND CAST(@secondDate AS TIME) <'18:00' 
                      OR
                      CAST(@firstDate AS TIME) >'18:00' AND CAST(@secondDate AS TIME) >='18:00' 
                  )
                  THEN DATEDIFF(day,@firstDate,@secondDate)
                  WHEN CAST(@firstDate AS TIME) <='18:00' AND CAST(@secondDate AS TIME) >='18:00' THEN DATEDIFF(day,@firstDate,@secondDate)+1 
                  ELSE DATEDIFF(day,@firstDate,@secondDate)-1
                  END
          END AS TotalCount
      

      【讨论】:

      • 嗨,我遇到了语法错误,但无法弄清楚它是什么 Msg 102,Level 15,State 1,Line 7 '
      • 不可能,使用我的 SQL,我只是再次测试
      • 一切皆有可能 :),也许我不知道不同的 SQL 版本。
      • :-) 这可能是个问题,无论您以何种方式得到答案
      • 我认为不是服务器问题,因为您显示的错误与版本无关
      【解决方案5】:

      一个简单的计数查询:

      DECLARE @StartDate datetime = '2017-04-17 18:00:00'
      
      DECLARE @EndDate datetime = '2017-04-19 18:00:00'
      
      SELECT 
         CASE 
            WHEN CAST(@StartDate AS time) <= '18:00' AND CAST(@EndDate AS time) >= '18:00' 
                   THEN datediff(day, @StartDate, @EndDate) + 1
            WHEN CAST(@StartDate AS time) <= '18:00' AND CAST(@EndDate AS time) < '18:00' 
                   THEN datediff(day, @StartDate, @EndDate)      
            WHEN CAST(@StartDate AS time) > '18:00' AND CAST(@EndDate AS time) >= '18:00' 
                   THEN datediff(day, @StartDate, @EndDate)
            ELSE datediff(day, @StartDate, @EndDate) - 1
         END AS TotalCount
      

      【讨论】:

      • 谢谢,这工作做得很好。
      【解决方案6】:
      DECLARE 
          @Time time = '18:00',
          @From datetime = '2017-04-17 18:00:00',
          @To datetime = '2017-04-19 18:00:00'
      
      
      SELECT 
          CASE 
              -- Same date
              WHEN DATEDIFF(DAY, @From, @To) = 0 THEN 
                  CASE WHEN CAST(CAST(@From AS date) AS datetime) + @Time BETWEEN @From AND @To THEN 1 ELSE 0 END
              -- Not same date
              WHEN @From <= @To THEN
                  CASE WHEN @Time >= CAST(@From AS time) THEN 1 ELSE 0 END 
                  + DATEDIFF(DAY, @From, @To) - 1
                  + CASE WHEN @Time <= CAST(@To AS time) THEN 1 ELSE 0 END 
              -- Invalid range
              ELSE 0
          END AS CountOfTime
      

      【讨论】:

        【解决方案7】:

        这将为您提供每小时和发生次数:

        select datepart(hh, DateColumn) as TheHours, count(*) as occurs
        from MyTable
        where DateColumn between @SomeDate and @SomeOtherDate
        group by datepart(hh, DateColumn)
        

        或者只是下午 6 点:

        select count(*)
        from MyTable
        where datepart(hh, DateColumn) = 18
        and DateColumn between @SomeDate and @SomeOtherDate
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-12-13
          • 2021-11-29
          • 1970-01-01
          • 2023-03-11
          • 2010-11-26
          • 1970-01-01
          • 2014-04-21
          • 1970-01-01
          相关资源
          最近更新 更多