Sql server 2005 查询缺少的元素

Sql server 2005 查询缺少的元素,sql-server-2005,null,common-table-expression,aggregates,Sql Server 2005,Null,Common Table Expression,Aggregates,我有一个具有以下结构的表: timestamp | name | value 0 | john | 5 1 | NULL | 3 8 | NULL | 12 12 | john | 3 33 | NULL | 4 54 | pete | 1 180 | NULL | 4 400 | john | 3 401 | NULL | 4 592 | anna | 2

我有一个具有以下结构的表:

timestamp | name | value
0         | john | 5
1         | NULL | 3
8         | NULL | 12
12        | john | 3
33        | NULL | 4
54        | pete | 1
180       | NULL | 4
400       | john | 3
401       | NULL | 4
592       | anna | 2
现在我要寻找的是一个查询,它将为我提供每个名称的值之和,并将按时间戳排序的两个空名称作为列表中的第一个非空名称,就像该表如下所示:

timestamp | name | value
0         | john | 5
1         | john | 3
8         | john | 12
12        | john | 3
33        | pete | 4
54        | pete | 1
180       | john | 4
400       | john | 3
401       | anna | 4
592       | anna | 2
我将按名称从这个表组中查询SUMvalue和name。我想了想,也试过了,但我想不出一个合适的解决办法。我已经研究了递归公共表表达式,并认为答案可能就在这里,但我还不能正确理解这些表达式

这些表只是示例,我事先不知道时间戳值

有人能帮我一下吗?非常感谢您的帮助

With Inputs As
    (
    Select 0 As [timestamp], 'john' As Name, 5 As value
    Union All Select 1, NULL, 3
    Union All Select 8, NULL, 12
    Union All Select 12, 'john', 3
    Union All Select 33, NULL, 4
    Union All Select 54, 'pete', 1
    Union All Select 180, NULL, 4
    Union All Select 400, 'john', 3
    Union All Select 401, NULL, 4
    Union All Select 592, 'anna', 2
    )
    , NamedInputs As
    (
    Select I.timestamp
        , Coalesce (I.Name
            ,   (
                Select I3.Name
                From Inputs As I3
                Where I3.timestamp = (
                                    Select Max(I2.timestamp)
                                    From Inputs As I2
                                    Where I2.timestamp < I.timestamp
                                        And I2.Name Is not Null
                                    )
                )) As name
        , I.value
    From Inputs As I
    )
Select NI.name, Sum(NI.Value) As Total
From NamedInputs As NI
Group By NI.name
顺便说一句,比任何查询都快几个数量级的是首先更正数据。也就是说,更新name列,使其具有正确的值,使其不可为null,然后运行一个简单的groupby来获取总数

附加解决方案


您不需要CTE,只需要一个简单的子查询

select t.timestamp, ISNULL(t.name, (
    select top(1) i.name
    from inputs i
    where i.timestamp < t.timestamp
    and i.name is not null
    order by i.timestamp desc
    )), t.value
from inputs t
从这里求和

select name, SUM(value) as totalValue
from
(
    select t.timestamp, ISNULL(t.name, (
        select top(1) i.name
        from inputs i
        where i.timestamp < t.timestamp
        and i.name is not null
        order by i.timestamp desc
        )) as name, t.value
    from inputs t
) N
group by name

我希望我不会因为向您提供我的这个小小的递归CTE查询作为您问题的解决方案而感到尴尬

;WITH
numbered_table AS (
  SELECT
    timestamp, name, value,
    rownum = ROW_NUMBER() OVER (ORDER BY timestamp)
  FROM your_table
),
filled_table AS (
  SELECT
    timestamp,
    name,
    value
  FROM numbered_table
  WHERE rownum = 1

  UNION ALL

  SELECT
    nt.timestamp,
    name = ISNULL(nt.name, ft.name),
    nt.value
  FROM numbered_table nt
    INNER JOIN filled_table ft ON nt.rownum = ft.rownum + 1
)
SELECT *
FROM filled_table
/* or go ahead aggregating instead */

嗨,托马斯,谢谢你的回答!我想我应该事先指定这是一个示例,它实际上是一个非常大的表,我事先不知道时间戳值。仍然感谢你让我走上正轨。@Martijn-在我的例子中,这不重要。我的输入CTE仅用于测试目的。您只需要调用NamedInputs CTE即可确定它应该为哪个名称分配NULL。我会说,如果你要这样做,一个更快的方法是更新数据,使列不可为空,然后运行求和。啊,我误解了。我将对我的实际数据进行一次运行和尝试,看看这是如何工作的。如果蛋糕符合我的需要,我会送它@Martijn-我发布了另一个可能的解决方案。然而,我仍然认为更正数据,然后直接查询表将是最好的方法。@Thomas,更新更可取,你完全正确。然而,这是来自封闭源代码第三方应用程序的数据。我担心更新会以我无法预料的方式破坏东西。我考虑过复制和更新,但我们谈论的是大量的数据。+1用于提供一些示例输入和预期输出,尽管您可能还包括对求和值的期望值。Cake会遇到不同颜色的大锤。@Thomas-好的,我以1个子查询级别获胜:结果相同,蛋糕将被授予最高速度。@Mar-Yes将有兴趣看到哪个更快。我打赌我也会试试的。我不认为它会很好地表现出来,但我在这方面是错的before@Martijn当前位置我也是。很高兴知道它在这种特殊情况下是否对您有效。
;WITH
numbered_table AS (
  SELECT
    timestamp, name, value,
    rownum = ROW_NUMBER() OVER (ORDER BY timestamp)
  FROM your_table
),
filled_table AS (
  SELECT
    timestamp,
    name,
    value
  FROM numbered_table
  WHERE rownum = 1

  UNION ALL

  SELECT
    nt.timestamp,
    name = ISNULL(nt.name, ft.name),
    nt.value
  FROM numbered_table nt
    INNER JOIN filled_table ft ON nt.rownum = ft.rownum + 1
)
SELECT *
FROM filled_table
/* or go ahead aggregating instead */