我正在使用Oracle SQL。
我有下表:
Timestamp | A | B
13-11-14 06.49.54.004 | 50 | 70
13-11-14 06.49.54.005 | NULL| 80
13-11-14 06.49.54.006 | NULL| NULL
13-11-14 06.49.54.007 | 40 | 70
13-11-14 06.49.54.008 | 20 | 90
13-11-14 06.49.54.009 | 30 | NULL
如何将NULL
值替换为每列的最后一个值?这是预期的输出表:
Timestamp | A | B
13-11-14 06.49.54.004 | 50 | 70
13-11-14 06.49.54.005 | 50 | 80
13-11-14 06.49.54.006 | 50 | 80
13-11-14 06.49.54.007 | 40 | 70
13-11-14 06.49.54.008 | 20 | 90
13-11-14 06.49.54.009 | 30 | 90
请告知。
答案 0 :(得分:5)
您可以将the first_value()
analytic function与windowing子句一起使用,使用timestamp列进行排序并忽略空值:
select timestamp, a, b,
first_value(a) ignore nulls over (order by timestamp desc
rows between current row and unbounded following) as new_a,
first_value(b) ignore nulls over (order by timestamp desc
rows between current row and unbounded following) as new_b
from table_name
order by timestamp;
TIMESTAMP A B NEW_A NEW_B
---------------------------- ---------- ---------- ---------- ----------
13-NOV-14 06.49.54.004000000 50 70 50 70
13-NOV-14 06.49.54.005000000 80 50 80
13-NOV-14 06.49.54.006000000 50 80
13-NOV-14 06.49.54.007000000 40 70 40 70
13-NOV-14 06.49.54.008000000 20 90 20 90
13-NOV-14 06.49.54.009000000 30 30 90
或者改为使用last_value():
select timestamp, a, b,
last_value(a) ignore nulls over (order by timestamp
rows between unbounded preceding and current row) as new_a,
last_value(b) ignore nulls over (order by timestamp
rows between unbounded preceding and current row) as new_b
from table_name
order by timestamp;
窗口包含当前行,因此如果该值不为null,则将使用它;否则它将使用第一个/最后一个非空值(因为ignore null
子句),因为它以指定的顺序遍历窗口。
答案 1 :(得分:1)
使用coalesce仅更新NULL,使用子选择来查找最新值。
update tablename t1 set a = coalesce(a,(select max(a) from tablename
where Timestamp < t1.Timestamp)),
b = coalesce(b,(select max(b) from tablename
where Timestamp < t1.Timestamp))
where a is null or b is null
现在编辑了! (最大可能不是最近的......)
update tablename t1 set a = coalesce(a,(select a from tablename
where Timestamp < t1.Timestamp
order by Timestamp desc
fetch first 1 row only)),
b = coalesce(b,(select b from tablename
where Timestamp < t1.Timestamp
order by Timestamp desc
fetch first 1 row only))
where a is null or b is null
FETCH FIRST需要更新的Oracle版本。
答案 2 :(得分:0)
我建议采用两种方法。首先,您可以非常轻松地使用PL / SQL块执行此操作,例如:
DECLARE
v_prev_timestamp TIMESTAMP;
v_prev_A INT;
v_prev_B INT;
BEGIN
FOR x IN (SELECT * FROM table_name) LOOP
IF (x.A IS NULL) THEN
UPDATE table_name SET A = v_prev_A where timestamp = v_prev_timestamp;
END IF;
... same for B ...
END LOOP;
END;
或者,您可以使用Oracle的LAG函数创建一个视图,该函数将使用前一行中的值覆盖空值。
CREATE VIEW table_name_no_nulls AS
SELECT timestamp,
nvl(A, lag(A) OVER (ORDER BY timestamp)) AS A,
nvl(B, lag(B) OVER (ORDER BY timestamp)) AS B
FROM table_name;
在第二个版本中,NVL在第一个参数中查找空值,如果为null,则将值替换为第二个参数的输入结果,即第二个参数的输入结果,即同一列的滞后值。您必须告诉Oracle如何对表进行排序,以便它知道要使用哪个以前的值。
我建议您使用第二个版本,因为您不需要运行任何一次性批次来更新数据。只需查询转换空值的新视图。
答案 3 :(得分:0)
有一个LEAD()和LAG()分析函数。在你的情况下,你需要LAG()。它非常易于使用,有大量示例 - 检查文档和搜索stackoverflow ...