如何用每组的前一列填充 NULL 列?
How to populate NULL column with the previous column per group?
如何用每组的前一行填充 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
,那么它应该填充相同 Product
类别中前一个 Amount
的 Amount
NULL
.
举个例子,上面是一个示例数据。
这一行
Date | Product | Amount
8/1/15 | Prod1 | NULL
它的数量应该用 5
填充,因为它应该在相同的 Product
类别中获得之前的值。
您需要这样的查询:
;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
我要建议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
的字符串永远不会太多,您可以这样做:
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;
直到没有行发生变化。
您可以使用 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. You can read more about the issue at MS-Connect.
如何用每组的前一行填充 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
,那么它应该填充相同Product
类别中前一个Amount
的Amount
NULL
.
举个例子,上面是一个示例数据。
这一行
Date | Product | Amount
8/1/15 | Prod1 | NULL
它的数量应该用 5
填充,因为它应该在相同的 Product
类别中获得之前的值。
您需要这样的查询:
;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
我要建议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
的字符串永远不会太多,您可以这样做:
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;
直到没有行发生变化。
您可以使用 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. You can read more about the issue at MS-Connect.