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

ofl*_*ero 5 sql t-sql sql-server date azure-sql-database

我目前正在运行一个聚合查询,汇总给定日期的销售量(比如)。

select convert(date, datetimesold), sum(amountsold) from tblSold 
group by convert(date, datetimesold)
Run Code Online (Sandbox Code Playgroud)

其中 datetimesold 是日期时间值。

convert(date,...)摆脱了时间价值,所以group by通过整整一天能集团。

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

datetimesold是 UTC 日期时间。所以我的问题是:假设我想按天分组,但在美国东部时间。在按以下方式在组中进行转换之前,我必须在 datetimesold 中添加一个以小时为单位的偏移量 - group by convert(date, dateadd(hours, -5, datetimesold))- 但即便如此,由于夏令时,这并不总是准确的 - EDT -4 小时,EST -5 小时。

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

编辑:为了进一步澄清,我在 Azure SQL 数据库上进行操作。

Vla*_*nov 3

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

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

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

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


至于您对表扫描的担忧 - 您始终必须扫描整个表才能计算SUM,因此额外的CONVERT todate并不重要。

另一方面,

如果您有一个单独的列仅存储date、 not datetime,则查询会更高效,因为date占用的字节数比 少datetime,因此从磁盘读取的字节数也更少。

如果在 上添加索引(datesold, amountsold),则GROUP BY不必进行额外的排序,这也使查询更加高效。


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