T-SQL 不同的截止日期
T-SQL Distinct Close Dates
使用 SQL Server 2005 我使用 UNION 从一组两个表中选择 DATETIME。其中许多非常接近:例如:
2016-01-29 10:28:57.540
2016-01-29 10:28:57.647
2016-01-29 11:23:18.193
2016-01-29 11:23:18.240
在这个例子中,我只想返回
2016-01-29 10:28:57.000
2016-01-29 11:23:18.000
这很容易使用一些 date/conversion 函数来删除 ms 部分。但是,如果我们得到以下信息:
2016-01-29 10:18:58.105
2016-01-29 10:18:57.952
2016-01-29 11:13:18.193
2016-01-29 11:13:18.240
当我只想要 2 个时,我会得到 3 个日期时间:
2016-01-29 10:18:58.000
2016-01-29 10:18:57.000
2016-01-29 11:13:18.000
而不是:
2016-01-29 10:18:58.000
2016-01-29 11:13:18.000
因为 2016-01-29 10:18:58.105 和 2016-01-29 10:18:57.952 相隔不到一秒。
所以问题是如何将彼此相差不到一秒的 DATETIME 值组合在一起?
为我的目的找到答案:
SELECT t1.UpdatedDateTime
FROM MyTable t1
LEFT JOIN MyTable t2 ON t1.UpdatedDateTime > t2.UpdatedDateTime AND t1.UpdatedDateTime < DATEADD(SECOND,1,t2.UpdatedDateTime)
WHERE t2.UpdatedDateTime IS NULL
加入 table 本身只会带回不是下一秒内时间的另一行的行。
决定你想要trim微秒的方式,然后按选择函数分组
select
DT,
-- Round down to nearest second
DT_Floor_MS =
dateadd(ms,-datepart(ms,a.DT),a.DT),
-- Round up to nearest second
DT_Ceiling_MS =
dateadd(ms,(1000-datepart(ms,a.DT))%1000,a.DT),
-- Round to nearest second
DT_Round_Off_MS =
dateadd(ms,500-((datepart(ms,a.DT)+500)%1000),a.DT)
from
(select --test data
'2016-01-29 10:28:57.540' DT union all select
'2016-01-29 10:28:57.647'union all select
'2016-01-29 11:23:18.193'union all select
'2016-01-29 11:23:18.240' ) a
DT DT_Floor_MS DT_Ceiling_MS DT_Round_Off_MS
2016-01-29 10:28:57.540 January, 29 2016 10:28:57 January, 29 2016 10:28:58 January, 29 2016 10:28:58
2016-01-29 10:28:57.647 January, 29 2016 10:28:57 January, 29 2016 10:28:58 January, 29 2016 10:28:58
2016-01-29 11:23:18.193 January, 29 2016 11:23:18 January, 29 2016 11:23:19 January, 29 2016 11:23:18
2016-01-29 11:23:18.240 January, 29 2016 11:23:18 January, 29 2016 11:23:19 January, 29 2016 11:23:18
select
dateadd(ms,(1000-datepart(ms,a.DT))%1000,a.DT)
-- Round to nearest second
from
(select --test data
'2016-01-29 10:28:57.540' DT union all select
'2016-01-29 10:28:57.647'union all select
'2016-01-29 11:23:18.193'union all select
'2016-01-29 11:23:18.240' ) a
group by
dateadd(ms,(1000-datepart(ms,a.DT))%1000,a.DT)
-- Round to nearest second
2016-01-29 10:28:58.000
2016-01-29 11:23:19.000
MS 更新 SQL 2005
DECLARE @TestDate AS TABLE (
dt DATETIME NOT NULL
)
INSERT INTO @TestDate (dt)
VALUES
('2016-01-29 10:18:58.105')
,('2016-01-29 10:18:57.952')
,('2016-01-29 11:13:18.193')
,('2016-01-29 11:13:18.240')
;WITH IdDt AS (
SELECT Id = ROW_NUMBER() OVER (ORDER BY dt)
,dt
FROM @TestDate)
SELECt IdDt.dt
FROM IdDt
LEFT JOIN IdDt LagDt ON IdDt.ID = LagDt.ID + 1
WHERE CASE WHEN DATEDIFF(MILLISECOND, LagDt.dt, IdDt.dt) < 1000 Then 0 ELSE 1 END = 1
MS SQL 服务器 2012 +
DECLARE @TestDate AS TABLE (
dt DATETIME NOT NULL
)
INSERT INTO @TestDate (dt)
VALUES
('2016-01-29 10:18:58.105')
,('2016-01-29 10:18:57.952')
,('2016-01-29 11:13:18.193')
,('2016-01-29 11:13:18.240')
SELECT dt
FROM (
SELECT dt, CASE WHEN DATEDIFF(MILLISECOND, LAG(dt) OVER (ORDER BY dt), dt) < 1000 Then 0 ELSE 1 END ToRemove
FROM @TestDate
) Filter
WHERE ToRemove = 1;
最简单直接的方法是使用日期时间秒近似值的 Distinct,如下所示:
SELECT DISTINCT DATEADD(MILLISECOND, 500 - DATEPART(MILLISECOND, TimeField + '00:00:00.500'),TimeField) FROM T1
使用 SQL Server 2005 我使用 UNION 从一组两个表中选择 DATETIME。其中许多非常接近:例如:
2016-01-29 10:28:57.540
2016-01-29 10:28:57.647
2016-01-29 11:23:18.193
2016-01-29 11:23:18.240
在这个例子中,我只想返回
2016-01-29 10:28:57.000
2016-01-29 11:23:18.000
这很容易使用一些 date/conversion 函数来删除 ms 部分。但是,如果我们得到以下信息:
2016-01-29 10:18:58.105
2016-01-29 10:18:57.952
2016-01-29 11:13:18.193
2016-01-29 11:13:18.240
当我只想要 2 个时,我会得到 3 个日期时间:
2016-01-29 10:18:58.000
2016-01-29 10:18:57.000
2016-01-29 11:13:18.000
而不是:
2016-01-29 10:18:58.000
2016-01-29 11:13:18.000
因为 2016-01-29 10:18:58.105 和 2016-01-29 10:18:57.952 相隔不到一秒。
所以问题是如何将彼此相差不到一秒的 DATETIME 值组合在一起?
为我的目的找到答案:
SELECT t1.UpdatedDateTime
FROM MyTable t1
LEFT JOIN MyTable t2 ON t1.UpdatedDateTime > t2.UpdatedDateTime AND t1.UpdatedDateTime < DATEADD(SECOND,1,t2.UpdatedDateTime)
WHERE t2.UpdatedDateTime IS NULL
加入 table 本身只会带回不是下一秒内时间的另一行的行。
决定你想要trim微秒的方式,然后按选择函数分组
select
DT,
-- Round down to nearest second
DT_Floor_MS =
dateadd(ms,-datepart(ms,a.DT),a.DT),
-- Round up to nearest second
DT_Ceiling_MS =
dateadd(ms,(1000-datepart(ms,a.DT))%1000,a.DT),
-- Round to nearest second
DT_Round_Off_MS =
dateadd(ms,500-((datepart(ms,a.DT)+500)%1000),a.DT)
from
(select --test data
'2016-01-29 10:28:57.540' DT union all select
'2016-01-29 10:28:57.647'union all select
'2016-01-29 11:23:18.193'union all select
'2016-01-29 11:23:18.240' ) a
DT DT_Floor_MS DT_Ceiling_MS DT_Round_Off_MS
2016-01-29 10:28:57.540 January, 29 2016 10:28:57 January, 29 2016 10:28:58 January, 29 2016 10:28:58
2016-01-29 10:28:57.647 January, 29 2016 10:28:57 January, 29 2016 10:28:58 January, 29 2016 10:28:58
2016-01-29 11:23:18.193 January, 29 2016 11:23:18 January, 29 2016 11:23:19 January, 29 2016 11:23:18
2016-01-29 11:23:18.240 January, 29 2016 11:23:18 January, 29 2016 11:23:19 January, 29 2016 11:23:18
select
dateadd(ms,(1000-datepart(ms,a.DT))%1000,a.DT)
-- Round to nearest second
from
(select --test data
'2016-01-29 10:28:57.540' DT union all select
'2016-01-29 10:28:57.647'union all select
'2016-01-29 11:23:18.193'union all select
'2016-01-29 11:23:18.240' ) a
group by
dateadd(ms,(1000-datepart(ms,a.DT))%1000,a.DT)
-- Round to nearest second
2016-01-29 10:28:58.000
2016-01-29 11:23:19.000
MS 更新 SQL 2005
DECLARE @TestDate AS TABLE (
dt DATETIME NOT NULL
)
INSERT INTO @TestDate (dt)
VALUES
('2016-01-29 10:18:58.105')
,('2016-01-29 10:18:57.952')
,('2016-01-29 11:13:18.193')
,('2016-01-29 11:13:18.240')
;WITH IdDt AS (
SELECT Id = ROW_NUMBER() OVER (ORDER BY dt)
,dt
FROM @TestDate)
SELECt IdDt.dt
FROM IdDt
LEFT JOIN IdDt LagDt ON IdDt.ID = LagDt.ID + 1
WHERE CASE WHEN DATEDIFF(MILLISECOND, LagDt.dt, IdDt.dt) < 1000 Then 0 ELSE 1 END = 1
MS SQL 服务器 2012 +
DECLARE @TestDate AS TABLE (
dt DATETIME NOT NULL
)
INSERT INTO @TestDate (dt)
VALUES
('2016-01-29 10:18:58.105')
,('2016-01-29 10:18:57.952')
,('2016-01-29 11:13:18.193')
,('2016-01-29 11:13:18.240')
SELECT dt
FROM (
SELECT dt, CASE WHEN DATEDIFF(MILLISECOND, LAG(dt) OVER (ORDER BY dt), dt) < 1000 Then 0 ELSE 1 END ToRemove
FROM @TestDate
) Filter
WHERE ToRemove = 1;
最简单直接的方法是使用日期时间秒近似值的 Distinct,如下所示:
SELECT DISTINCT DATEADD(MILLISECOND, 500 - DATEPART(MILLISECOND, TimeField + '00:00:00.500'),TimeField) FROM T1