如何根据指定的时区有效地按日期分组?

时间:2016-04-13 10:10:17

标签: sql sql-server tsql date azure-sql-database

我目前正在运行汇总查询,在给定日期汇总销售金额(比如说)。

select convert(date, datetimesold), sum(amountsold) from tblSold 
group by convert(date, datetimesold)

其中datetimesold是日期时间值。

convert(date,...)删除了时间值,因此group by可以整天分组。

这已经不是很有效了,因为它需要对每行转换进行表格扫描 - 更好的方法是添加“dateold”'只包含日期值的列,已建立索引,并且每次都在插入时包含此值。但这会失去该列的精确度,这很重要,因为......

datetimesold是UTC日期时间。所以我的问题是:说我想在白天分组,但在美国东部时间。我必须在小组之前添加一个小时到几小时的偏移量,然后再按照group by convert(date, dateadd(hours, -5, datetimesold))进行转换 - 但即使这样,由于夏令时,这也不会总是准确的 - 美国东部时间4点,美国东部时间 - 5个小时。

我是否有任何有效的选择在SQL中执行此操作?我可以在这里使用任何时区感知功能吗?

编辑:为了进一步说明,我正在使用Azure SQL数据库。

3 个答案:

答案 0 :(得分:3)

您已经注意到很难正确地从UTC转换为本地时区。事实上,这是非常困难的,因为夏令时的规则会发生变化。您需要维护一个历史的时区数据库才能正确完成。

我存储两个时间戳 - 以UTC和本地时区。在一些报告中,我们需要UTC,在某些地方。

通常,当插入行并且生成数据的客户端计算机的操作系统位于正确的本地时区时,很容易在UTC和本地时区之间进行转换。那时OS知道本地和UTC时间。但是,如果您拥有前几年的历史数据,那么执行此类转换将变得更加困难。

SQL Server 2016承诺为时区添加更好的支持,请参阅:AT TIME ZONE

至于您对表格扫描的关注 - 您将始终必须扫描整个表格以计算SUM,因此额外CONVERTdate并不重要。< / p>

另一方面,

如果您有一个仅存储date而不是datetime的单独列,则查询效率会更高一些,因为date占用的字节数少于datetime,所以从磁盘读取的字节数更少。

如果您在(datesold, amountsold)上添加索引,则GROUP BY无需进行额外排序,这也可以提高查询效率。

因此,在当前版本的SQL Server中,我会添加一个索引date列,其中包含报告所需时区的日期。如果需要UTC和美国东部时区的报告,我会添加两个单独的date列。

答案 1 :(得分:0)

如果可以某种方式访问​​时区名称,则可以使用SQL date函数的变体,该变体接受标准时区字符串,例如

select
    date(date, @timezone_name) as dte, sum(amountsold) from tblSold 
    group by dte

其中@timezone_name是以下任何值:

select * from sys.time_zone_info 

(SQL 2016 +)

答案 2 :(得分:-1)

尝试将值转换为您的组的日期类型。

GROUP BY CAST(myDateTime AS DATE)

管理时区,你可以使用.net api nodatime并使其成为CLR SQL函数,将有助于解决UTC日期时间问题。

http://nodatime.org/