【问题标题】:How to find gaps of data and insert NULL data points instead having gap如何找到数据间隙并插入 NULL 数据点而不是有间隙
【发布时间】:2014-01-03 20:14:09
【问题描述】:

我有一个列集(假设 A 列和 B 列)。 每列可以有多个点(日期时间和值)。 每个列集都有预定义的时间步长。下面的例子是:600 秒。

A 栏

dateTime - '2013-10-05 00:10:00' 
Value - 0.51231
dateTime - '2013-10-05 00:20:00' 
Value - 0.54123
dateTime - '2013-10-05 00:30:00' 
Value - 0.53312
...
dateTime - '2013-11-14 13:30:00' 
Value - 0.53312

etc.

B 列

dateTime - '2013-10-05 00:10:00' 
Value - 0.51231
dateTime - '2013-10-05 00:20:00' 
Value - 0.54123
dateTime - '2013-10-05 00:50:00' 
Value - 0.54123
...
dateTime - '2013-11-14 13:20:00' 
    Value - 0.53312
dateTime - '2013-11-14 13:30:00' 
Value - 0.53312
dateTime - '2013-11-14 13:40:00' 
Value - 0.53312

我需要为每列查找缺失的数据点并插入 NULL 点,以便所有列都有准确的点数。

对于上述示例,缺少的数据点是:

columnA - 2013-11-14 13:40:00
columnB - 2013-10-05 00:30:00, 2013-10-05 00:40:00

我知道我可以对给定列集的每一列使用 T-SQL 或 PHP(客户端)进行迭代并检查每个点,但我认为这会很慢。尤其是 PHP 解决方案。

可能有智能 SQL 能够选择缺失的日期时间(间隔)。

有什么想法吗?

更新: 因为不清楚数据库结构。 列是表中的一个字段,所以,让我们有一个表:tblValues。 有 3 个字段:columnName、datetime 和 value。 在我们的示例中,columnName 是 columnA 或 columnB。

【问题讨论】:

  • 不清楚您的表格在这里是什么样子。 “columnA”是一个有两列的表吗?你能发布你的 CREATE TABLE 语句吗?
  • 我在最后更新了问题。
  • 你怎么知道缺少一个值?
  • 我的逻辑是没有值就没有数据点。然而,数据库结构需要有 NULL 数据点,这是没有数据点的信息。这样的记录必须存在,因为数据对齐......基本上由于一些限制我无法改变它。

标签: sql-server datetime


【解决方案1】:

还不错。这里的关键是保留一个数字表。它只是一个包含一列和数字 1 到任意数量的表格。它们非常有用。这是我最喜欢的创建方法 (courtesy of Itzik Ben-Gan):

;WITH
  Pass0 as (select 1 as C union all select 1), --2 rows
  Pass1 as (select 1 as C from Pass0 as A, Pass0 as B),--4 rows
  Pass2 as (select 1 as C from Pass1 as A, Pass1 as B),--16 rows
  Pass3 as (select 1 as C from Pass2 as A, Pass2 as B),--256 rows
  Pass4 as (select 1 as C from Pass3 as A, Pass3 as B),--65536 rows
  Pass5 as (select 1 as C from Pass4 as A, Pass4 as B),--4,294,967,296 rows
  Tally as (select row_number() over(order by C) as Number from Pass5)
 select Number INTO dbo.Numbers from Tally where Number <= 1000000

现在你就是我的,它只是一个使用数字表来生成其中数据的应 em>的是,然后离开它加入到你真正有问题。像这样的:

WITH [data] AS (SELECT * FROM (VALUES 
    ('2013-10-05 00:10:00', 0.51231),
    ('2013-10-05 00:20:00', 0.54123),
    ('2013-10-05 00:30:00', 0.53312),
    ('2013-10-05 00:50:00', 0.54123)
) AS x(d, v)),
[times] AS (
    SELECT TOP 10 DATEADD(MINUTE, 10*[Number], '2013-10-05') AS [d]
    FROM dba.dbo.[Numbers] AS n
)
SELECT * FROM [times] 
LEFT JOIN [data]
    ON [times].d = [data].d
WHERE [data].d IS NULL

【讨论】:

  • 我还没有尝试过,但看起来效果很好。我希望有内置的日历/数字表。我将首先尝试该解决方案。谢谢。
  • 可以使用SSAS生成时间表technet.microsoft.com/en-us/library/ms174832.aspx
  • 很好地使用 cte 和交叉连接来生成大量数字!
  • 我已经使用该表几个月了,但注意到我的应用程序中存在严重错误。检查它发生的原因,我无法相信我的 Number 表中的记录没有正确排序。行从 1 开始,Number 等于行号,直到 3332,但 3333 行包含 49029 个数字,最后一行 1000000 包含 41412 个数字。当我删除该表并重新创建后,问题就消失了,但我如何知道 tblNumbers 中的行是否更改了我的顺序?
  • 表没有隐式排序。因此,当您说“我的 Number 表中的记录没有正确排序”时,这并不意味着什么。只有当您“选择 ... order by ”时,result set 才会进行排序。
【解决方案2】:

我不太确定您的表结构是什么样的,但假设您尝试在 10 分钟内查找没有后继的行,您可以进行自联接:

-- Example schema
CREATE TABLE ExampleData (ValueDate datetime, Value int)
INSERT INTO ExampleData
VALUES ('2013-01-01 14:00:00', 1),
    ('2013-01-01 14:10:00', 1),
-- this row will be found as there is a gap
    ('2013-01-01 14:20:00', 1),
-- gap ends
    ('2013-01-01 14:40:00', 1)

-- Query    
SELECT gs.ValueDate as [Start of Gap], ge.ValueDate as [End of Gap], 
    gs.Value as [Value at start of gap], ge.Value as [Value at end of gap]
FROM (
    -- correlate all values with their successors
    SELECT gl.ValueDate, gl.Value, MIN(gh.ValueDate) as NextValueDate
    FROM ExampleData gl
    LEFT OUTER JOIN ExampleData gh on gl.ValueDate < gh.ValueDate
    GROUP BY gl.ValueDate, gl.Value
) as gs
LEFT OUTER JOIN ExampleData ge on gs.NextValueDate = ge.ValueDate
-- limit to only those values which have gaps of greater than 600 seconds
WHERE ge.ValueDate > DATEADD(second, 600, gs.ValueDate) OR ge.ValueDate is null

--Results:
--Start of Gap            End of Gap              Value at start of gap Value at end of gap
------------------------- ----------------------- --------------------- -------------------
--2013-01-01 14:20:00.000 2013-01-01 14:40:00.000 1                     1
--2013-01-01 14:40:00.000 NULL                    1                     NULL

【讨论】:

  • 不错的方法,但是它给了我日期范围的空白。我仍然需要以某种方式列出缺失点以执行插入。
【解决方案3】:

超级困惑的问题,这是另一个想法......

您可以为您关心的时间范围生成一个日期时间值表(通过您自己的脚本或使用 SSAS 生成时间维度表)。在 datetimevalues 表上执行 while 循环,在循环内查询您的表以获取该时间戳,然后确保该查询的结果包含您需要的所有列。为任何缺失的列写入新行。 这样的事情可能会有所帮助

    declare @temp table tempRes (columnname varchar(100))
    declare @timestamptable table (ts datetime)
insert @timestamptable select ts from mygeneratedTSTable
    while exists(select '' from @timestamptable)
    begin
        declare @ts datetime
        set @ts = (select top 1 ts from ts);
    --insert all the entries you have for the given timestamp
        insert @temp select distinct columnname from yourdata where yourTScol = @ts
    --now check to see if you are missing columns... if you have a lot of columns to check for
    --then do this part smarter
            if not exists (select '' from @temp where columnname = 'column a')
            begin
                insert into yourdata values('column a',null)
            end
            if not exists (select '' from @temp where columnname = 'column b')
            begin
                insert into yourdata values('column b',null)
            end
            --clear out the temp
        delete from @temp
        --remove this top element so the loop will terminate
        delete top (1) from @timestamptable
    end

希望这会有所帮助 此外,除了 IF 块之外,您还可以将列名列表和外连接设置为 @temp 表中的结果,然后插入任何具有空引用的行。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-02-28
    • 1970-01-01
    • 1970-01-01
    • 2020-10-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多