SQL服务器如何避免WHERE子句中的时区转换

SQL Server how to avoid Time Zone conversion in WHERE clause

我必须检索特定日期 太平洋标准时间 之间的行,但数据库将日期列存储为 UTC。目前,我在 WHERE 子句中进行转换,但这会花费很多时间,因为我在 WHERE 子句中使用了一个函数,这会导致完整的 table 扫描。

SELECT T.foo
FROM table T
JOIN .... ON ....
WHERE CONVERT(DATETIME,SWITCHOFFSET(T.start_date_utc,DATEPART(TZOFFSET, T.start_date_utc AT TIME ZONE 'Pacific Standard Time'))) BETWEEN '1/1/2018 00:00:00 AM' AND '2/28/2018 23:59:59 PM'

没有WHERE子句中的转换函数,有没有更好的方法呢?

其他信息:

我试过的:

另一种方法是将您的输入更改为 UTC。这是一次性操作,SQL 更容易过滤。以下是根据您的 sql 版本实现相同目标的不同方法。

-- 1
WHERE T.start_date_utc
     BETWEEN '1/1/2018 08:00:00 AM' /*PST to UTC*/
        AND '2/28/2018 07:59:59 PM' /*PST to UTC*/
-- 2    
WHERE T.start_date_utc
 BETWEEN DATEADD(HOUR, 8, '1/1/2018 00:00:00 AM'),  /*PST to UTC*/
    AND DATEADD(HOUR, 8, '2/28/2018 23:59:59 PM' /*PST to UTC*/

-- 3
WHERE T.start_date_utc
     BETWEEN SWITCHOFFSET('1/1/2018 00:00:00 AM', '-08:00') /*PST to UTC*/
        AND SWITCHOFFSET('2/28/2018 23:59:59 PM', '-08:00') /*PST to UTC*/


/*Avoiding hard coded values*/

-- 4
DECLARE @offset INT

 SELECT @offset = DATEPART(TZOFFSET, CONVERT(datetime,'1/1/2018 00:00:00 AM') AT TIME ZONE 'Pacific Standard Time') * -1

 WHERE T.start_date_utc
 BETWEEN DATEADD(MINUTE, @offset, '1/1/2018 00:00:00 AM'),  /*PST to UTC*/
    AND DATEADD(MINUTE, @offset, '2/28/2018 23:59:59 PM' /*PST to UTC*/

-- 5        
WHERE T.start_date_utc
     BETWEEN CONVERT(datetime,'1/1/2018 00:00:00 AM')  AT TIME ZONE 'Pacific Standard Time' /*PST to UTC*/
        AND CONVERT(datetime,'2/28/2018 23:59:59 PM')  AT TIME ZONE 'Pacific Standard Time' /*PST to UTC*/

现在,您正在对所有数据进行时区转换。相反,弄清楚正确的 UTC 时间戳应该是什么,然后将您的数据与之进行比较。像这样:

declare @startTimePST datetime = '1/1/2018 00:00:00 AM',
    @endTimePST datetime = '2/28/2018 23:59:59 PM';

declare @startTimeUTC datetime = @startTimePST 
    at time zone 'Pacific Standard Time' 
    at time zone 'UTC',
  @endTimeUTC datetime = @endTimePST 
    at time zone 'Pacific Standard Time' 
    at time zone 'UTC';

select @startTimePST, @startTimeUTC, 
    @endTimePST, @endTimeUTC

SELECT T.foo
FROM table T
JOIN .... ON ....
WHERE T.start_date_utc BETWEEN @startTimeUTC AND @endTimeUTC;

作为说明,我正在声明变量并为它们分配代表您的 PST 时间戳的值。然后我通过双重使用 at time zone 子句将它们转换为 UTC。为什么是两个?第一个将 PST 时区附加到您的无时区时间戳,然后将 those 转换为 UTC。一旦我有了这些端点,我就可以直接在查询中使用它们。