T-SQL DateDiff - 按“整小时前”进行分区,而不是“时间分钟变成 00 以来”
Posted
技术标签:
【中文标题】T-SQL DateDiff - 按“整小时前”进行分区,而不是“时间分钟变成 00 以来”【英文标题】:T-SQL DateDiff - partition by "full hours ago", rather than "times minutes turned 00 since" 【发布时间】:2010-07-20 11:45:27 【问题描述】:我有一个带有时间戳的表,我想将这个表划分为一个小时的间隔,从现在开始,倒退几个小时。我无法使用 T-SQL DATEDIFF 函数获得所需的结果,因为它计算分针在两个日期之间经过 12 的次数 - 我想要分针经过的次数 现在在时间戳和现在之间的位置。
在 T-SQL 中是否有直接的方法来执行此操作?
更新: 针对cmets,这里有一些示例数据,我目前正在使用的查询和我得到的结果,以及我想要的结果。
样本数据:
TimeStamp
*********
2010-07-20 11:00:00.000
2010-07-20 10:44:00.000
2010-07-20 10:14:00.000
2010-07-20 11:00:00.000
2010-07-20 11:40:00.000
2010-07-20 10:16:00.000
2010-07-20 13:00:00.000
2010-07-20 12:58:00.000
当前查询:
SELECT TimeStamp, DATEDIFF(HOUR, TimeStamp, CURRENT_TIMESTAMP) AS Diff FROM ...
结果:
时间戳差异 ********* **** 2010-07-20 11:00:00.000 2 2010-07-20 10:44:00.000 3 2010-07-20 10:14:00.000 3 2010-07-20 11:00:00.000 2 2010-07-20 11:40:00.000 2 2010-07-20 10:16:00.000 3 2010-07-20 13:00:00.000 0 2010-07-20 12:58:00.000 1
我宁愿拥有什么:
-- 举例来说,现在是 13:40 时间戳差异 ********* **** 2010-07-20 11:00:00.000 3 -- +1 2010-07-20 10:44:00.000 3 2010-07-20 10:14:00.000 4 -- +1 2010-07-20 11:00:00.000 3 -- +1 2010-07-20 11:40:00.000 2 或 3 -- 边缘情况,我真的不在乎哪个 2010-07-20 10:16:00.000 4 -- +1 2010-07-20 13:00:00.000 1 -- +1 2010-07-20 12:58:00.000 1
我已用+1
标记了更改的结果。另外,我真的不在乎这是 0 索引还是 1 索引,但基本上,如果现在是 13:40,我希望获得相同值的时间跨度是
12:40-13:40 1 (或 0) 11:40-12:40 2(或1) 10:40-11:40 3(或2) 09:40-10:40 4(或3)
【问题讨论】:
你能解释一下输入数据和查询的预期输出,你已经写了吗? DATEDIFF 以分钟为单位然后整数除以 60? 【参考方案1】:你能不能只使用DATEDIFF(minute,..
然后将结果除以60并取整数值。例如
SELECT DATEDIFF(minute, '2010-07-20 06:00', GETDATE())/60
我相信这将被隐式转换为 int,因为 datediff 返回一个 int,它给出了整个小时而没有四舍五入。
要使用您更新帖子中的确切查询:
SELECT TimeStamp, (DATEDIFF(minute, TimeStamp, CURRENT_TIMESTAMP) /60) AS Diff FROM ...
【讨论】:
这仍然不准确。您刚刚将错误从 59 分钟更改为 59 秒... @Emtucifor:59 秒的错误仍然要好得多 - 我将使用它来决定用户是否应该收到通知,并且他们最多只能收到一个小时。在这种情况下,59 分钟的错误是灾难性的 - 59 秒的错误非常好。而且我什至可以通过用秒做同样的事情来让错误更小( 好的,那没问题。不过,我更喜欢我的减日期版本,因为它更简单,并且与数据类型允许的一样精确。 :)【参考方案2】:您可以对此进行分组:
SELECT DateDiff(Hour, 0, GetDate() - TimeStamp)
如果您想知道这代表的时间,请将其计算回去:
DateAdd(Hour, -DateDiff(Hour, 0, GetDate() - TimeStamp), GetDate())
如果您不喜欢减去日期,那么它仍然可以完成,但会变得有点困难。我没有在黑暗中拍摄,而是提出了一个查询来证明这是正确的。
SELECT
TimeStamp,
Now = GetDate(),
HourDiff = DateDiff(Hour, 0, GetDate() - TimeStamp),
HourCalc = DateAdd(Hour, -DateDiff(Hour, 0, GetDate() - TimeStamp), GetDate()),
HourDiff2 = DateDiff(Hour, DateAdd(Millisecond, AdjustMs, TimeStamp), DateAdd(Millisecond, AdjustMs, GetDate())),
HourCalc2 = DateAdd(Hour, -DateDiff(Hour, DateAdd(Millisecond, AdjustMs, TimeStamp), DateAdd(Millisecond, AdjustMs, GetDate())), GetDate())
FROM
(
SELECT DateAdd(Second, -3559, GetDate())
UNION ALL SELECT DateAdd(Second, -3600, GetDate())
UNION ALL SELECT DateAdd(Second, -3601, GetDate())
) x (TimeStamp)
CROSS JOIN (
SELECT 3599997 - DateDiff(Millisecond, 0, DateAdd(Hour, -DateDiff(Hour, 0, GetDate()), GetDate()))
) D (AdjustMs)
不幸的是,我不得不利用我对 datetime 数据类型的分辨率(1/300 秒)的了解,因此 3600000 - 3 = 3599997。如果毫秒调整是根据 TimeStamp 而不是 GetDate() 计算的,那么这将' 不是必需的,但这会更麻烦,因为派生表 D 中的大表达式必须在主查询中使用两次,替换 AdjustMs。
计算比看起来需要的要复杂,因为您不能只计算随机日期之间的毫秒差,否则会出现溢出错误。如果您知道可能的日期范围,则可以使用与“19000101 00:00:00.000”(上述表达式中的 0)不同的锚日期进行直接毫秒计算。
再想一想,您只能将 24 天以上的毫秒转换为有符号长:
SELECT DateAdd(Millisecond, 2147483647, 0) = '1900-01-25 20:31:23.647'
【讨论】:
避免减去日期似乎有很长的路要走-但从您的帖子中我认为可能有充分的理由不想这样做。为什么我不想减去日期? 好吧,在这种情况下 datetime 不是必需的,但在 SQL Server 2008 中,您不能添加或减去 date 的值b> 数据类型。虽然现在使用 datetime 这样做是可行的,但它可能不会永远。 C#.Net 也禁止这样做(您只能从日期或其他时间跨度中添加和减去时间跨度)所以我们都应该考虑如何避免它,如果我们要长期掌握这些东西。某天减去日期时间可能会被弃用,然后作为一项功能被删除!【参考方案3】:我会用
FLOOR(24 * CAST(CURRENT_TIMESTAMP-[TimeStamp] as float))
测试用例
DECLARE @GetDate datetime
set @GetDate = '2010-07-20 13:40:00.000';
WITH TestData As
(
select CAST('2010-07-20 11:00:00.000' AS DATETIME) AS [TimeStamp] UNION ALL
select '2010-07-20 10:44:00.000' UNION ALL
select '2010-07-20 10:14:00.000' UNION ALL
select '2010-07-20 11:00:00.000' UNION ALL
select '2010-07-20 11:40:00.000' UNION ALL
select '2010-07-20 10:16:00.000' UNION ALL
select '2010-07-20 13:00:00.000' UNION ALL
select '2010-07-20 12:58:00.000'
)
SELECT [TimeStamp], FLOOR(24 * CAST(@GetDate-[TimeStamp] as float)) AS Diff
FROM TestData
结果
(您需要添加 1 才能获得您发布的确切结果,但您说您不会为 0 或 1 索引而烦恼)
TimeStamp Diff
----------------------- ----------------------
2010-07-20 11:00:00.000 2
2010-07-20 10:44:00.000 2
2010-07-20 10:14:00.000 3
2010-07-20 11:00:00.000 2
2010-07-20 11:40:00.000 2
2010-07-20 10:16:00.000 3
2010-07-20 13:00:00.000 0
2010-07-20 12:58:00.000 0
【讨论】:
为什么是24 *
? CAST(@GetDate-[TimeStamp] AS FLOAT)
给了我什么?
@Tomas。 CAST(@GetDate-[TimeStamp] AS FLOAT)
是天数差。例如1.75 将是 1 天和 18 小时的差异。所以乘以 24 得到小时数的差异。使用Floor
然后将一小时内的所有内容组合在一起。
Martin,根据我的经验,转换为浮点数对于日期时间来说是不可靠的。我过去仔细研究过这个。 Datediff(Hour, 0, Current_TimeStamp - TimeStamp) 做同样的事情。以上是关于T-SQL DateDiff - 按“整小时前”进行分区,而不是“时间分钟变成 00 以来”的主要内容,如果未能解决你的问题,请参考以下文章