我有2列
date number
---- ------
1 3
2 NULL
3 5
4 NULL
5 NULL
6 2
.......
我需要用新值取代NULL值,取值来自日期列中上一个日期的最后一个已知值 例如:date = 2 number = 3,date 4 and 5 number = 5 and 5. NULL值随机出现。
答案 0 :(得分:20)
如果您使用的是Sql Server,则应该可以使用
DECLARE @Table TABLE(
ID INT,
Val INT
)
INSERT INTO @Table (ID,Val) SELECT 1, 3
INSERT INTO @Table (ID,Val) SELECT 2, NULL
INSERT INTO @Table (ID,Val) SELECT 3, 5
INSERT INTO @Table (ID,Val) SELECT 4, NULL
INSERT INTO @Table (ID,Val) SELECT 5, NULL
INSERT INTO @Table (ID,Val) SELECT 6, 2
SELECT *,
ISNULL(Val, (SELECT TOP 1 Val FROM @Table WHERE ID < t.ID AND Val IS NOT NULL ORDER BY ID DESC))
FROM @Table t
答案 1 :(得分:15)
这是一个MySQL解决方案:
UPDATE mytable
SET number = (@n := COALESCE(number, @n))
ORDER BY date;
这是简洁的,但在其他品牌的RDBMS中不一定有效。对于其他品牌,可能会有一个更具相关性的品牌特定解决方案。这就是为什么告诉我们你正在使用的品牌很重要的原因。
独立于供应商很高兴,正如@Pax所评论的那样,但如果失败了,那么使用您所选择的数据库品牌也是一件好事。
以上查询的说明:
@n
是MySQL用户变量。它从NULL开始,并在UPDATE遍历行时为每一行分配一个值。如果number
为非NULL,@n
的值为number
。如果number
为NULL,则COALESCE()
默认为先前的@n
值。在任何一种情况下,这都成为number
列的新值,UPDATE进入下一行。 @n
变量在行与行之间保留其值,因此后续行获取来自前一行的值。 UPDATE的顺序是可预测的,因为MySQL特别使用ORDER BY和UPDATE(这不是标准的SQL)。
答案 2 :(得分:9)
最佳解决方案是Bill Karwin提供的解决方案。我最近不得不在一个相对较大的结果集中解决这个问题(1000行,每列12列,如果此值在当前行为null,则显示最后一个非空值)并使用更高方法选择上一个已知值(或带有前1个的子查询)运行速度超慢。
我使用的是SQL 2005,变量替换的语法与mysql略有不同:
UPDATE mytable
SET
@n = COALESCE(number, @n),
number = COALESCE(number, @n)
ORDER BY date
如果'number'不为null,则第一个set语句将变量@n的值更新为当前行的'number'值(COALESCE返回您传入的第一个非null参数) 第二个set语句将'number'的实际列值更新为自身(如果不为null)或变量@n(始终包含遇到的最后一个非NULL值)。
这种方法的优点在于,一遍又一遍地扫描临时表没有额外的资源... @n的行内更新负责跟踪最后一个非空值。
我没有足够的代表投票给他的答案,但有人应该。它是最优雅,性能最佳的。
答案 3 :(得分:8)
以下是Oracle解决方案(10g或更高版本)。它使用带有last_value()
选项的分析函数ignore nulls
,该选项替换列的最后一个非空值。
SQL> select *
2 from mytable
3 order by id
4 /
ID SOMECOL
---------- ----------
1 3
2
3 5
4
5
6 2
6 rows selected.
SQL> select id
2 , last_value(somecol ignore nulls) over (order by id) somecol
3 from mytable
4 /
ID SOMECOL
---------- ----------
1 3
2 3
3 5
4 5
5 5
6 2
6 rows selected.
SQL>
答案 4 :(得分:6)
以下脚本解决了此问题,仅使用普通的ANSI SQL。我在SQL2008,SQLite3和Oracle11g上测试了此解决方案。
CREATE TABLE test(mysequence INT, mynumber INT);
INSERT INTO test VALUES(1, 3);
INSERT INTO test VALUES(2, NULL);
INSERT INTO test VALUES(3, 5);
INSERT INTO test VALUES(4, NULL);
INSERT INTO test VALUES(5, NULL);
INSERT INTO test VALUES(6, 2);
SELECT t1.mysequence, t1.mynumber AS ORIGINAL
, (
SELECT t2.mynumber
FROM test t2
WHERE t2.mysequence = (
SELECT MAX(t3.mysequence)
FROM test t3
WHERE t3.mysequence <= t1.mysequence
AND mynumber IS NOT NULL
)
) AS CALCULATED
FROM test t1;
答案 5 :(得分:4)
我知道这是一个非常古老的论坛,但我在解决问题时遇到了这个问题:)刚才意识到其他人已经给出了上述问题的复杂解决方案。请参阅下面的解决方案:
DECLARE @A TABLE(ID INT, Val INT)
INSERT INTO @A(ID,Val) SELECT 1, 3
INSERT INTO @A(ID,Val) SELECT 2, NULL
INSERT INTO @A(ID,Val) SELECT 3, 5
INSERT INTO @A(ID,Val) SELECT 4, NULL
INSERT INTO @A(ID,Val) SELECT 5, NULL
INSERT INTO @A(ID,Val) SELECT 6, 2
UPDATE D
SET D.VAL = E.VAL
FROM (SELECT A.ID C_ID, MAX(B.ID) P_ID
FROM @A AS A
JOIN @A AS B ON A.ID > B.ID
WHERE A.Val IS NULL
AND B.Val IS NOT NULL
GROUP BY A.ID) AS C
JOIN @A AS D ON C.C_ID = D.ID
JOIN @A AS E ON C.P_ID = E.ID
SELECT * FROM @A
希望这可以帮助某人:)
答案 6 :(得分:2)
在一般意义上说:
UPDATE MyTable
SET MyNullValue = MyDate
WHERE MyNullValue IS NULL
答案 7 :(得分:2)
如果您正在寻找Redshift的解决方案,这将适用于frame子句:
SELECT date,
last_value(columnName ignore nulls)
over (order by date
rows between unbounded preceding and current row) as columnName
from tbl
答案 8 :(得分:1)
首先,您真的需要存储值吗?您可以使用执行该任务的视图:
SELECT t."date",
x."number" AS "number"
FROM @Table t
JOIN @Table x
ON x."date" = (SELECT TOP 1 z."date"
FROM @Table z
WHERE z."date" <= t."date"
AND z."number" IS NOT NULL
ORDER BY z."date" DESC)
如果您确实拥有ID ("date")
列并且它是主键(群集),那么此查询应该非常快。但请检查查询计划:包含Val
列的封面索引可能更好。
另外,如果您不喜欢可以避免使用的程序,也可以对UPDATE
使用类似的查询:
UPDATE t
SET t."number" = x."number"
FROM @Table t
JOIN @Table x
ON x."date" = (SELECT TOP 1 z."date"
FROM @Table z
WHERE z."date" < t."date" --//@note: < and not <= here, as = not required
AND z."number" IS NOT NULL
ORDER BY z."date" DESC)
WHERE t."number" IS NULL
注意:代码必须适用于“SQL Server”。
答案 9 :(得分:1)
这是MS Access的解决方案。
示例表名为tab
,其中包含字段id
和val
。
SELECT (SELECT last(val)
FROM tab AS temp
WHERE tab.id >= temp.id AND temp.val IS NOT NULL) AS val2, *
FROM tab;
答案 10 :(得分:1)
这将在Snowflake上起作用(归功于Darren Gardner):
create temp table ss (id int, val int);
insert into ss (id,val) select 1, 3;
insert into ss (id,val) select 2, null;
insert into ss (id,val) select 3, 5;
insert into ss (id,val) select 4, null;
insert into ss (id,val) select 5, null;
insert into ss (id,val) select 6, 2;
select *
,last_value(val ignore nulls) over
(order by id rows between unbounded preceding and current row) as val2
from ss;
答案 11 :(得分:0)
UPDATE TABLE
SET number = (SELECT MAX(t.number)
FROM TABLE t
WHERE t.number IS NOT NULL
AND t.date < date)
WHERE number IS NULL
答案 12 :(得分:0)
如果您具有一个身份(Id
)和一个公共(Type
)列:
UPDATE #Table1
SET [Type] = (SELECT TOP 1 [Type]
FROM #Table1 t
WHERE t.[Type] IS NOT NULL AND
b.[Id] > t.[Id]
ORDER BY t.[Id] DESC)
FROM #Table1 b
WHERE b.[Type] IS NULL
答案 13 :(得分:-3)
试试这个:
update Projects
set KickOffStatus=2
where KickOffStatus is null