【问题标题】:Filter datetime columns in SQL Server在 SQL Server 中筛选日期时间列
【发布时间】:2018-12-11 22:01:29
【问题描述】:

我有一个 datetime 列,在下一个数据之间有 5 分钟的间隔,但是我想查看该列是否包含小于 5 分钟的任何时间间隔,尤其是 5 秒。

例如:

  • 有一个日期是2018-05-04 19:21:46.000
  • 下一行将显示2018-05-04 19:26:46.000
  • 2018-05-04 19:31:46.000

但是,我们有时会得到如下行:

  • 2018-05-04 19:36:46.000
  • 然后2018-05-04 19:36:51.000
  • 然后2018-05-04 19:36:56.000

什么 SQL 脚本最适合过滤列以区分错误数据(5 秒间隔)和正确数据(5 分钟间隔),尤其是在包含数千行的表中?

嗨@Andrea,谢谢。我有一些问题。 “q”代表什么?当我将查询重写为

SELECT  ProductID, MyTimestamp, DATEDIFF(second, xMyTimestamp, MyTimestamp) as DIFFERENCE_IN_SECONDS
FROM    (
        SELECT  *,
                Lag(MyTimestamp) OVER (ORDER BY MyTimestamp, ProductID) as xMyTimestamp
        FROM    TableName
        ) q
WHERE   xMyTimestamp IS NOT NULL and ProductID= 31928

我得到的结果不能准确计算时间。

+-----------+-------------------------+-----------------------+
| ProductID |       MyTimestamp       | DIFFERENCE_IN_SECONDS |
+-----------+-------------------------+-----------------------+
|     31928 | 2017-03-21 13:36:30.000 |                     0 |
|     31928 | 2017-03-21 13:46:30.000 |                     0 |
|     31928 | 2017-03-21 13:56:32.000 |                     0 |
|     31928 | 2017-03-21 14:01:32.000 |                     0 |
|     31928 | 2017-03-21 14:11:32.000 |                     0 |
|     31928 | 2017-03-21 14:16:32.000 |                     0 |
|     31928 | 2017-03-21 14:26:32.000 |                     0 |
|     31928 | 2017-03-21 14:36:32.000 |                     0 |
+-----------+-------------------------+-----------------------+

任何理由

【问题讨论】:

  • 假设下一条记录是“正确的”,会是什么? 19:41:46 还是 19:41:56?
  • @WolfgangK,如果我正确理解了您的问题,则以秒为单位的差异字段中的正确记录不应读取为零,而是计算 Mytimestamp 中的后续值与 MyTimestamp 中的先前值之间的时间差场地。所以它应该是 600, 602, 300, 600, 300 等等,但它却是 0。
  • 不,你没看懂我的问题,而且由于样本数据已经留下了问题,所以你不能。我的问题是:下一个“正确”值是在最后一个“正确”值之后 5 分钟还是在最后一个记录之后 5 分钟,无论它是否正确?对于“差异 0”:按 ProductID 分区并将其从 Order By 中删除。该问题的最可能原因是多个产品同时使用。

标签: sql-server tsql datetime sql-server-2014


【解决方案1】:

你可以使用LAG:

declare @tmp table(MyTimestamp datetime)

insert into @tmp values
('2018-05-04 19:21:46.000')
,('2018-05-04 19:26:46.000')
,('2018-05-04 19:31:46.000')
,('2018-05-04 19:36:46.000')
,('2018-05-04 19:36:51.000')
,('2018-05-04 19:36:56.000')


SELECT  DATEDIFF(second, xMyTimestamp, MyTimestamp) as DIFFERENCE_IN_SECONDS
FROM    (
        SELECT  *,
                LAG(MyTimestamp) OVER (ORDER BY MyTimestamp) xMyTimestamp
        FROM    @tmp
        ) q
WHERE   xMyTimestamp IS NOT NULL

结果:

所以你应该这样使用它:

SELECT  DATEDIFF(second, xMyTimestamp, MyTimestamp) as DIFFERENCE_IN_SECONDS
FROM    (
        SELECT  *,
                LAG(MyTimestamp) OVER (ORDER BY MyTimestamp) xMyTimestamp
        FROM    [YOUR_TABLE_NAME_HERE]
        ) q
WHERE   xMyTimestamp IS NOT NULL

编辑

这是另一个基于 OP 发布的新数据的示例:

declare @tmp table(ProductID int, MyTimestamp datetime)

insert into @tmp values
 (31928, '2017-03-21 13:36:30.000')
,(31928, '2017-03-21 13:46:30.000')
,(31928, '2017-03-21 13:56:32.000')
,(31928, '2017-03-21 14:01:32.000')
,(31928, '2017-03-21 14:11:32.000')
,(31928, '2017-03-21 14:16:32.000')
,(31928, '2017-03-21 14:26:32.000')
,(31928, '2017-03-21 14:36:32.000')

SELECT ProductID
    ,MyTimestamp
    ,DATEDIFF(second, xMyTimestamp, MyTimestamp) AS DIFFERENCE_IN_SECONDS
FROM (
    SELECT *
        ,Lag(MyTimestamp) OVER (
            ORDER BY MyTimestamp
                ,ProductID
            ) AS xMyTimestamp
    FROM @tmp
    ) q
WHERE xMyTimestamp IS NOT NULL
    AND ProductID = 31928

输出:

Here你可以检查计算结果是否正确。

【讨论】:

  • 谢谢安德里亚,这看起来很棒,但表格有数千行,我想我不必插入那么多值。然后选择差异。
  • @DBANewbie 这只是向您展示该解决方案有效的示例。您现在必须忽略脚本的 insert 部分,并将 @tmp 替换为您的实际表名。查看更新的答案。
  • 嗨@Andrea,感谢您的回复。更多问题请查看原帖
  • @DBANewbie q 只是使用子查询所需的别名。我用您提供的值测试了代码:它工作正常。请查看更新的答案和 Rextester 链接。
  • 谢谢@Andrea。我看到了,除了您将这些值插入到表变量中之外,这是完全相同的查询。我正在尝试从一个大表中检索这些结果,但我没有看到我在最后一列中没有得到正确的计算。
【解决方案2】:

由于您是 2014 年,您可以使用 LEAD 将一行的值与下一行的值进行比较。

declare @table table(id int identity(1,1), interval datetime)
insert into @table
values
('2018-05-04 19:21:46.000'),
('2018-05-04 19:26:46.000'),
('2018-05-04 19:31:46.000'),

('2018-05-04 19:36:46.000'),
('2018-05-04 19:36:51.000'),
('2018-05-04 19:36:56.000')

select
    id
    ,interval
    ,issue_with_row = case 
                            when 
                                isnull(datediff(minute,interval,lead(interval) over (order by id, interval)),0) < 5 
                            then 1 
                            else 0 
                        end
from @table
order by id

或者如果你只想看到那些,

;with cte as(
select
    id
    ,interval
    ,issue_with_row = case 
                            when 
                                isnull(datediff(minute,interval,lead(interval) over (order by id, interval)),0) < 5 
                            then 1 
                            else 0 
                        end
from @table)

select *
from cte 
where issue_with_row = 1

【讨论】:

  • 感谢@scsimon,但您的第二个查询是否针对具有无限行的表而不是我提供的示例进行调整。
  • 是的,@DBANewbie 只是用你的表替换它
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-22
  • 2014-08-09
  • 2010-12-10
  • 2015-01-21
相关资源
最近更新 更多