【问题标题】:T-SQL Overlapping time range parameter in stored procedure存储过程中的 T-SQL 重叠时间范围参数
【发布时间】:2014-07-15 01:27:59
【问题描述】:

我想搜索发生在一天中特定时间和日期/时间范围之间的记录。

示例:

我的桌子:

ID | EmpID |  AuthorizationTime
-------------------------------
1  | 21455 | '23/01/2012 12:44'
2  | 22311 | '23/01/2012 18:15'
3  | 21455 | '23/01/2012 23:04'
4  | 10222 | '24/01/2012 03:31'
5  | 21456 | '24/01/2012 09:00'
6  | 53271 | '25/01/2012 12:15'
7  | 10222 | '26/01/2012 18:30'
8  | 76221 | '27/01/2012 09:00'

示例 SP 输入参数:

@from:  22/01/2012 08:00
@to:    24/01/2012 23:00
@fromtime:  18:30
@totime:    08:00

预期输出:

EntryID EmployeeID  AuthorisationTime
3       21455       '23/01/2012 23:04'
4       10222       '24/01/2012 03:31'

我在 SP 中尝试了以下选择语句:

...
Select @wAuthorizationTime=' AuthorizationTime between ''' + CONVERT(nvarchar(30), @from )+ ''' and ''' + convert(nvarchar(50),@to )+ ''' '

Select @Where = @wAuthorizationTime; Declare @wHours nvarchar(1000)='';
    if (ISNULL(@fromtime,'')<>'' and ISNULL(@ToTime,'')<> '') begin Select @wHours= ' (Cast(AuthorizationTime as time) between ''' + @fromTime + ''' and '''+ @ToTime +''')' 
    end if (@wHours <> '') Select @Where=@Where + ' and ' + @wHours

...

此语句的问题在于,如果结束时间低于开始时间(例如 23:00 到 03:00),我不会得到任何结果。

如果我使用不重叠的时间范围(例如 18:00 到 23:59),它确实有效。

我需要做什么才能获得上述结果?

【问题讨论】:

    标签: sql tsql stored-procedures sql-server-2008-r2


    【解决方案1】:

    添加检查以查看是否为@fromtime &gt; @totime。如果是这种情况,请像这样比较 AuthorizationTime 的 TIME-casted 值:

    (cast(AuthorizationTime as time) between '00:00:00' and @totime) or
    (cast(AuthorizationTime as time) between @fromtime and '23:59:59.999')
    

    【讨论】:

      【解决方案2】:

      这应该会给你你想要的:

      select *
      from Times
      where AuthorizationTime >= @from
      and AuthorizationTime <= @to
      and (
              (@fromtime > @totime and ((cast(AuthorizationTime as time) between '00:00:00' and @totime) or 
                                        (cast(AuthorizationTime as time) between @fromtime and '23:59:59.999')
                                       )
              ) or
             (@fromtime <= @totime and cast(AuthorizationTime as time) between @fromtime and @totime)
          )
      

      SQL Fiddle

      【讨论】:

        【解决方案3】:

        -- 在 SELECT 语句之前做一些复杂的事情

        declare @from DateTime,
        @to DateTime, 
        @fromTime int,
        @totime int
        
        -- sample data:
            set @from = convert(datetime, '22/01/2012 08:00', 103)
            set @to = convert(varchar, '24/01/2012 23:00', 103)
        
        -- first truncte the date
           set @from = convert(datetime, convert(varchar, @from, 103), 103)
           set @to = convert(datetime, convert(varchar, @to, 103), 103)
        
        -- then build the time as an int: Hour * 100 + Minute
            set @fromTime = 1830 
            set @toTime = 800 -- note this is an int
        
        
        -- Then use this to do the where clause:
            select *
            from myTable
            where AuthorisationTime between @from and @to
            and (DATEPART(HOUR, AuthorizationTime) * 100 + DATEPART(MINUTE, AuthorizationTime) 
                 >= @fromTime OR 
                  DATEPART(HOUR, AuthorizationTime) * 100 + DATEPART(MINUTE, AuthorizationTime) 
                <= @toTime)
        

        我认为这很容易理解、测试,并且更有可能利用索引。

        【讨论】:

        • 这不起作用。问题的关键在于@fromTime 有时大于@toTime。另外,我在测试数据上进行了尝试,它没有返回任何行。
        • @Jerrad,你说得对,我的 fromTime 和 toTime 倒退了。我在回答中更改了它。不确定截断日期是否也是您想要的。
        • 这不是我的问题,我只是正在寻找答案的其他人。但是,它仍然没有返回任何行。 @JBrooks
        • 我做到了。请参阅下面的答案。
        • @Jerrad 我也把日期倒过来了(到,从)。现在已解决此问题,我得到 2 行包含您的示例数据。感谢您指出这一点。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-09-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-10-03
        • 2013-05-28
        相关资源
        最近更新 更多