SQL填充缺口与hold

时间:2017-08-24 15:19:54

标签: sql sql-server tsql fill

我遇到了一个我无法用我的知识解决的问题,而且我找不到任何我理解得足以解决问题的解决方案。

所以这就是我试图实现的目标。 我有一个具有以下结构的数据库:

node_id, source_time, value
1      , 10:13:15   ,  1
2      , 10:13:15   ,  1
2      , 10:13:16   ,  2
1      , 10:13:19   ,  2
1      , 10:13:25   ,  3
2      , 10:13:28   ,  3

我想要一个sql查询来获取以下输出

   time , value1, value2
10:13:15,    1  ,    1
10:13:16,    1  ,    2
10:13:19,    2  ,    2
10:13:25,    3  ,    2
10:13:28,    3  ,    3 

你看,时间都是从两个节点发生的。 但是值必须填补空白,因为node1没有时间值:16和:28。 我得到了它从一张桌子得到2列的地步。那不是困难的部分。

SELECT T1.[value], T2.[value] 
FROM [db1].[t_value_history] T1, [db1].[t_value_history] T2 
WHERE ( T1.node_id = 1 AND T2.node_id = 2)

但结果看起来并不像我想要的那样。

我在COALESCE和另一个保存前一个值的表中找到了一些东西。但对于这么简单的事情来说,这看起来很安静。 我想有一个简单的SQL解决方案,但我没有太多时间进入材料。

我很乐意知道使用哪种功能。

到目前为止,谢谢。

编辑:更改了数据库,在最后一行犯了错误。

Edit2:我正在使用SQL Server。很抱歉没有说明这一点。此值也不是必然增加。我刚刚在这个例子中使用了越来越多的数字。

3 个答案:

答案 0 :(得分:0)

您可以使用条件聚合来获取正确的行集:

select vh.source_time,
       max(case when vh.node_id = 1 then value end) as value_1,
       max(case when vh.node_id = 2 then value end) as value_2
from db1.t_value_history vh
group by vh.source_time;

如果您想填写这些值,那么最佳解决方案是lag() ignore nulls。 ANSI支持,但不支持SQL Server(我猜你正在使用它)。您的值似乎在增加。如果是这种情况,您可以使用累计最大值:

select vh.source_time,
       max(max(case when vh.node_id = 1 then value end)) over (order by vh.source_time) as value_1,
       max(max(case when vh.node_id = 2 then value end) over (order by vh.source_time) as value_2
from db1.t_value_history vh
group by vh.source_time;

在您的数据中,value正在增加,因此这适用于您示例中的数据。如果不是这种情况,则需要更复杂的查询来填补空白。

答案 1 :(得分:0)

这将在SQL Server中执行。但它并不“好”:

SELECT DISTINCT
T1.source_time,
CASE WHEN T1.node_id = 1 THEN T1.[value] ELSE ISNULL(T2.[value], T3.[value]) END,
CASE WHEN T1.node_id = 1 THEN ISNULL(T2.[value], T3.[Value]) ELSE T1.[value] END
FROM
[db1].[t_value_history] T1
LEFT OUTER JOIN [db1].[t_value_history] T2 ON T2.source_time = T1.source_time
AND T2.node_id <> T1.node_id -- This join looks for a value for the other node at the same time.
LEFT OUTER JOIN [db1].[t_value_history] T3 ON T3.source_time < T1.source_time
AND T3.node_id <> T1.node_id -- If the previous join is empty, this looks for values for the other node at previous times
LEFT OUTER JOIN [db1].[t_value_history] T4 ON T4.source_time > T3.source_time
AND T4.source_time < T1.source_time
AND T4.node_id <> T1.node_id -- This join makes sure there aren't any more recent values
WHERE
T4.node_id IS NULL

答案 2 :(得分:0)

这适用于SQL Server。如果您确定在最短时间内两个节点都有值,那么您可以将OUTER APPLY更改为CROSS APPLY,这将表现更好。

WITH    times
          AS ( SELECT DISTINCT
                        source_time
               FROM     dbo.t_value_history
             )
    SELECT  t.source_time ,
            n1.value ,
            n2.value
    FROM    times AS t
            OUTER APPLY ( SELECT TOP 1
                                    h.value
                          FROM      dbo.t_value_history AS h
                          WHERE     h.node_id = 1
                                    AND h.source_time <= t.source_time
                          ORDER BY  h.source_time DESC
                        ) AS n1
            OUTER APPLY ( SELECT TOP 1
                                    h.value
                          FROM      dbo.t_value_history AS h
                          WHERE     h.node_id = 2
                                    AND h.source_time <= t.source_time
                          ORDER BY  h.source_time DESC
                        ) AS n2;