如何使用每个组的上一列填充NULL列?

时间:2015-07-21 14:26:20

标签: sql sql-server null

如何在每组的前一行填充NULL值?

说出类似的话,

+--------+---------+--------+
| Date   | Product | Amount |
+        +         +        +
| 7/1/15 | Prod1   | 5      |
| 7/1/15 | Prod2   | 7      |
| 7/1/15 | Prod3   | 9      |
| 8/1/15 | Prod1   | NULL   |
| 8/1/15 | Prod2   | 8      |
| 8/1/15 | Prod3   | NULL   |
| 9/1/15 | Prod1   | 1      |
| 9/1/15 | Prod2   | NULL   |
| 9/1/15 | Prod3   | NULL   |
| 10/1/15| Prod1   | NULL   |
+--------+---------+--------+

实现这样的目标:

+--------+---------+--------+
| Date   | Product | Amount |
+        +         +        +
| 7/1/15 | Prod1   | 5      |
| 7/1/15 | Prod2   | 7      |
| 7/1/15 | Prod3   | 9      |
| 8/1/15 | Prod1   | 5      |
| 8/1/15 | Prod2   | 8      |
| 8/1/15 | Prod3   | 9      |
| 9/1/15 | Prod1   | 1      |
| 9/1/15 | Prod2   | 8      |
| 9/1/15 | Prod3   | 9      |
| 10/1/15| Prod1   | 1      |
+--------+---------+--------+

这有意义吗?我不知道从哪里开始。任何帮助将非常感激。谢谢!

修改

规则:

  • 如果Amount列为NULL,则应使用同一Amount类别中的Amount的{​​{1}}填充,而不是Product 1}}。

比如说,上面是一个示例数据。

这一行

NULL

它的数量应该填充Date | Product | Amount 8/1/15 | Prod1 | NULL ,因为它应该在相同的5类别中获取它之前的值。

3 个答案:

答案 0 :(得分:2)

您可以使用ISNULL(或COALESCE)和相关子查询:

SELECT  t.Date, t.Product, 
        Amount = ISNULL(t.Amount, 
                  (SELECT TOP 1 Amount 
                   FROM dbo.TableName t2
                   WHERE t2.Product = t.Product
                   AND t2.Amount IS NOT NULL
                   AND t2.Date <= t.Date
                   ORDER BY t2.Date DESC))
FROM dbo.TableName t

Demo 包含您的样本数据。

我更喜欢ISNULL而不是CAOLESCE,因为后者will be translated to a CASE that is executed twice。您可以详细了解该问题at MS-Connect

答案 1 :(得分:0)

您需要这样的查询:

;WITH t AS (
    SELECT *, ROW_NUMBER() OVER (PARTITION BY Product ORDER BY [Date]) rn
    FROM yourTable)
, tt AS (
    SELECT t1.[Date], t1.Product, t1.Amount, MAX(CASE WHEN t2.Amount IS NOT NULL THEN t2.rn END) AS LastSeq
    FROM t t1
    LEFT JOIN
    t t2 ON t1.Product = t2.Product AND t2.rn <= t1.rn
    GROUP BY t1.[Date], t1.Product, t1.Amount)
SELECT tt.[Date], tt.Product, ISNULL(tt.Amount, t.Amount) As Amount
FROM tt 
JOIN t ON tt.Product = t.Product AND tt.LastSeq = t.rn  
ORDER BY tt.[Date], tt.Product

答案 2 :(得分:0)

我将建议cross apply

update table t cross apply
       (select top 1 t2.*
        from table t2
        where t2.product = t.product and
              t2.date < t.date and
              t2.amount is not null
        order by t2.date desc
       ) toupdate
    set amount = toupdate.amount
    where t.amount is null;

编辑:

如果您知道NULL s字符串永远不会太多,您可以执行以下操作:

update table t
     set product = coalesce(lag(amount) over (partition by product order by date),
                            lag(amount, 2) over (partition by product order by date),
                            lag(amount, 3) over (partition by product order by date)
                           )
     where product is null;

或者,或者,只需运行:

update table t
     set product = lag(amount) over (partition by product order by date)
     where product is null;

直到没有行改变。