更新值而不是NULL

时间:2015-02-17 15:01:41

标签: sql oracle null

我正在使用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

请告知。

4 个答案:

答案 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 ...