SQL QUERY使用前一个已知值的值replace行中的NULL值
我有2列
date number ---- ------ 1 3 2 NULL 3 5 4 NULL 5 NULL 6 2 .......
我需要用新的值replaceNULL值取自date列中前一个date的最后一个已知值的值,例如:date = 2 number = 3,date 4和5 number = 5和5.出现NULL值随机。
如果你正在使用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
这是一个MySQL解决scheme:
UPDATE mytable SET number = (@n := COALESCE(number, @n)) ORDER BY date;
这是简洁的,但不会在其他品牌的RDBMS工作。 对于其他品牌,可能会有更具针对性的品牌特定解决scheme。 这就是为什么告诉我们你使用的品牌很重要。
像@Pax评论的那样,独立于供应商是很好的,但如果不这样做,那么使用您select的数据库品牌也是非常好的。
上述查询的解释:
@n
是一个MySQL用户variables。 它从NULL开始,并在UPDATE在行中运行时在每行上分配一个值。 其中number
是非NULL,@n被赋值为number
的值。 如果number
是NULL,则COALESCE()
默认为@n
的前一个值。 在任何一种情况下,这都会成为number
列的新值,UPDATE会继续到下一行。 @n
variables在行之间保留它的值,所以后面的行得到来自前一行的值。 UPDATE的顺序是可以预测的,因为MySQL特别使用ORDER BY和UPDATE(这不是标准的SQL)。
最好的解决scheme是Bill Karwin提供的解决scheme。 我最近不得不用一个相对较大的结果集来解决这个问题(1000行,每行12列,如果这个值在当前行为null,则需要显示最后一个非空值),并使用top 1的update方法select以前已知的值(或顶部1的子查询)运行速度超慢。
我正在使用SQL 2005和variablesreplace语法略有不同于MySQL:
UPDATE mytable SET @n = COALESCE(number, @n), number = COALESCE(number, @n) ORDER BY date
如果'number'不是null(COALESCE返回你传入的第一个非null参数),第一个set语句将variables@n的值更新为当前行的'number'值第二个set语句更新实际(如果不为空)或variables@n(它始终包含遇到的最后一个非NULL值)的“number”列值。
这种方法的好处在于,不需要额外的资源来重复扫描临时表… @n的行内更新负责跟踪最后一个非空值。
我没有足够的代表投票答复,但有人应该。 这是最优雅和最好的表演。
这里是Oracle解决scheme(10g或更高版本)。
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>
我知道这是一个非常古老的论坛,但是在解决我的问题的同时我遇到了这个问题:)刚刚意识到其他人已经给上述问题提供了一点复杂的解决scheme。 请参阅下面的解决scheme:
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
希望这可能有助于某人:)
以下脚本解决了这个问题,只使用普通的ANSI SQL。 我在SQL2008 , SQLite3和Oracle11g上testing了这个解决scheme。
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;
从一般意义上说:
UPDATE MyTable SET MyNullValue = MyDate WHERE MyNullValue IS NULL
首先,你真的需要存储的价值? 你可以使用这个工作的观点:
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”上工作。
这是MS Access的解决scheme。
示例表被称为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;
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
如果你正在寻找一个Redshift的解决scheme,这将适用于框架条款:
SELECT date,last_value(columnName ignore nulls)over(根据datesorting,在无界前面和当前行之间的行)作为columnName从tbl
尝试这个:
update Projects set KickOffStatus=2 where KickOffStatus is null