【问题标题】:Group by datetime ignoring time portion按日期时间分组,忽略时间部分
【发布时间】:2011-09-13 22:36:53
【问题描述】:

是否可以编写一个按 datetime 数据类型分组但忽略时间部分(例如小时和分钟)的 Microsoft SQL 查询?

【问题讨论】:

  • 什么版本的 SQL Server?对于这个特定的问题,它确实很重要。 (在所有版本的 SQL Server 中可能,但在 2008+ 有更好的解决方案)
  • @AndriyM - 按datetimedate 部分分组确实存在一个特定的优化问题,而不仅仅是截断日期部分。例如比较CREATE TABLE T1(D DATETIME2 PRIMARY KEY);CREATE TABLE T2(D DATE, T TIME, PRIMARY KEY(D,T));SELECT COUNT(*) FROM T1 GROUP BY CAST(D AS DATE) OPTION (ORDER GROUP);SELECT COUNT(*) FROM T2 GROUP BY D OPTION (ORDER GROUP)的计划
  • @MartinSmith:啊,好点子!这是一个很好的例子,证明了我在发现一个简单的重复时过度渴望,我的投票很接近!尽管如此,如果我今天在这个问题上遇到问题,我可能不会认识到你刚才指出的特殊性,所以感谢你为我(以及其他所有人)标记了差异。

标签: sql sql-server datetime time group-by


【解决方案1】:

如果您使用的是 SQL Server 2008,这很简单。

GROUP BY CAST(YourCol AS Date)

对于以前的版本,您可以使用

GROUP BY DATEDIFF(DAY, 0, YourCol)

但是,这些都无法利用YourCol 上的索引由datetime 排序也将由date 排序这一事实,因此使用流聚合而无需排序操作。

在 SQL Server 2008+ 上,您可能会考虑索引 (date,time) 而不是 datetime 以促进此类查询。

通过简单地将其存储为两个单独的组件并可能提供一个重新组合各部分的计算列(datetime2datetime 存储相同,因此不会占用更多空间除非附加列将NULL_BITMAP 推送到新字节上。)。

CREATE TABLE T
(
YourDateCol date,
YourTimeCol time,
YourDateTimeCol AS  DATEADD(day, 
                            DATEDIFF(DAY,0,YourDateCol), 
                            CAST(YourTimeCol AS DATETIME2(7)))
/*Other Columns*/
)

或者,您可以将其组合存储在基表中,并让索引使用计算列将其拆分。

这种方法的一个例子

CREATE TABLE T
(
DT DATETIME2,
D AS CAST(DT AS DATE),
T AS CAST(DT AS TIME)
)

CREATE INDEX IX1 ON T(DT);

SELECT COUNT(*), 
       CAST(DT AS DATE)
FROM T
GROUP BY CAST(DT AS DATE)

CREATE INDEX IX2 ON T(D,T);

SELECT COUNT(*), 
       CAST(DT AS DATE)
FROM T
GROUP BY CAST(DT AS DATE)

DROP TABLE T

【讨论】:

  • GROUP BY DATEDIFF(DAY, 0, YourCol) 在这种情况下可能也足够了......
  • @Tomalak - 好点。这将返回一个足够 group byint,并且没有理由转换回 datetime,除非用于显示目的。
【解决方案2】:

如果您有一张大表并希望快速进行分组,则不能依靠表达式进行分组。

在您的表上创建一个额外的日期时间列,并由一个触发器填充它,该触发器根据您的“真实”日期计算基准日期:

UPDATE
  MyTable
SET
  EffectiveDate = DATEADD(DAY, 0, DATEDIFF(DAY, 0, t.RecordDate))
FROM
  MyTable t
  INNER JOIN inserted i ON i.RowID = t.RowID

然后将索引放在EffectiveDate 上,分组(和搜索)会快很多。

【讨论】:

  • 对于 SQL Server 2008 按日期is sargable 强制转换,尽管我没有检查这是否在group by 查询中得到利用。
  • @Martin 有趣,我不知道。但是当列上没有索引时它仍然会触发表扫描,不是吗?
  • 为什么是触发器而不是计算列? EffectiveDate AS CONVERT(DATETIME, DATEADD(DAY, 0, DATEDIFF(DAY, 0, t.RecordDate))) - 此列也可以保留和索引,以消除对可搜索性的任何疑虑,而无需支付触发器的开销。
  • @Aaron 没错。 SQL Server 2000 不支持具有日期时间值的计算列上的索引(由于某些原因,日期函数在那里是不确定的)。这已在以后的版本中得到修复,但我一开始仍然认为“触发”。 ;)
猜你喜欢
  • 2019-01-23
  • 2011-10-22
  • 1970-01-01
  • 1970-01-01
  • 2011-12-02
  • 1970-01-01
  • 2018-01-25
  • 2012-02-18
  • 2016-02-14
相关资源
最近更新 更多