我目前正在运行一个聚合查询,汇总给定日期的销售量(比如)。
select convert(date, datetimesold), sum(amountsold) from tblSold
group by convert(date, datetimesold)
其中 datetimesold 是日期时间值。
convert(date,...)
去掉时间值,所以 group by
可以全天分组。这已经不是很有效了,因为它需要对每行的转换进行表扫描 - 更好的方法是添加一个仅包含日期值的“datesold”列,索引,并在每次插入时包含此值。但这会失去该列的精度,这很重要,因为......
datetimesold
是 UTC 日期时间。所以我的问题是:假设我想按天分组,但在美国东部时间。在通过 - group by convert(date, dateadd(hours, -5, datetimesold))
在组中进行转换之前,我必须向 datetimesold 添加一个以小时为单位的偏移量- 但即便如此,由于夏令时,这也不会总是准确的 - EDT -4 小时,EST -5 小时。在 SQL 中我是否有任何有效的选择来执行此操作?我可以在这里使用任何时区感知功能吗?
编辑:为了进一步澄清,我在 Azure SQL 数据库上进行操作。
最佳答案
您已经注意到很难正确地从 UTC 转换为本地时区。事实上,这非常困难,因为夏令时的规则发生了变化。您需要维护时区的历史数据库才能正确执行此操作。
我存储两个时间戳 - UTC 和本地时区。在某些报告中,我们需要 UTC,在某些本地报告中。
通常,当插入行并且生成数据的客户端计算机的操作系统处于正确的本地时区时,UTC 和本地时区之间的转换很容易。那时操作系统知道本地时间和 UTC 时间。但是,如果您拥有前几年的历史数据,则执行此类转换将变得更加困难。
SQL Server 2016 promise 为时区添加更好的支持,请参阅:AT TIME ZONE .
至于您对表扫描的担忧 - 您总是必须扫描整个表来计算 SUM
,所以额外 CONVERT
至 date
真的没有关系。
另一方面,
如果您有一个单独的列只存储 date
,不是 datetime
,查询效率会更高一些,因为 date
占用的字节数少于 datetime
,因此从磁盘读取的字节数更少。
如果您在 (datesold, amountsold)
上添加索引,然后是 GROUP BY
不必进行额外的排序,这也使查询更加高效。
因此,在当前版本的 SQL Server 中,我会添加一个索引 date
列将包含报告所需的时区中的日期。如果需要 UTC 和美国东部时区的报告,我会添加两个单独的 date
列。
关于sql - 如何有效地按指定时区的日期分组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36595203/