首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >SQL将多行字段的空值填充为以前的非空值。

SQL将多行字段的空值填充为以前的非空值。
EN

Stack Overflow用户
提问于 2016-11-26 08:14:58
回答 5查看 1.7K关注 0票数 2

我在netezza中有一个表(基于postgresql),如下所示。我需要为name创建一个包含空值的新表,并将其替换为上一个非空行的name值。

table1

代码语言:javascript
运行
复制
id name time    value
---------------------
1 john  11:00   324
2 NULL  12:00   645
3 NULL  13:00   324
4 bane  11:00   132
5 NULL  12:00   30
6 NULL  13:00   NULL
7 NULL  14:00   -1
8 zane  11:00   152
9 NULL  12:00   60
10 NULL 13:00   NULL

输出表

代码语言:javascript
运行
复制
name    time    value
---------------------
john    11:00   324
john    12:00   645
john    13:00   324
bane    11:00   132
bane    12:00   30
bane    13:00   NULL
bane    14:00   -1
zane    11:00   152
zane    12:00   60
zane    13:00   NULL

注:

  1. 由于权限限制,无法更改table1,因此采用新表的方式。
  2. 需要在Netezza (最好是)或MS Access中运行。

用于在Netezza中创建测试数据的代码如下所示。

代码语言:javascript
运行
复制
create temp table test (
    id int
    ,name varchar(10)
    ,time time
    ,value int
)distribute on random;

insert into test (id, name, time, value) values(1, 'joe', '10:00', 324);
insert into test (id, name, time, value) values(2, null, '11:00', 645);
insert into test (id, name, time, value) values(3, null, '12:00', 324);

insert into test (id, name, time, value) values(4, 'bane', '10:00', 132);
insert into test (id, name, time, value) values(5, null, '11:00', 30);
insert into test (id, name, time, value) values(6, null, '12:00', null);
insert into test (id, name, time, value) values(7, null, '13:00', -1);

insert into test (id, name, time, value) values(8, 'zane', '10:00', 152);
insert into test (id, name, time, value) values(9, null, '11:00', 60);
insert into test (id, name, time, value) values(10, null, '12:00', null);
EN

回答 5

Stack Overflow用户

发布于 2016-11-26 11:26:08

试试这个递归的PostgreSQL查询:

代码语言:javascript
运行
复制
WITH RECURSIVE t(id, name, time, value) AS (
  SELECT id, name, time, value FROM test WHERE id = (
    SELECT MIN(id) FROM test
  )
  UNION
  SELECT test.id, COALESCE(test.name, t.name), test.time, test.value
  FROM test, t WHERE test.id = (
    SELECT id FROM test WHERE id > t.id ORDER BY id LIMIT 1
  )
) SELECT * FROM t ORDER BY id;

但是请注意,这可能会在每一行上发出一个SELECT。如果不需要,可以使用视图解决方案:

代码语言:javascript
运行
复制
CREATE VIEW test_view AS
SELECT id, LAG(id) OVER (ORDER BY id) lag_id, name, time, value FROM test;

WITH RECURSIVE t(id, name, time, value) AS (
  SELECT id, name, time, value FROM test_view WHERE lag_id IS NULL
  UNION ALL
  SELECT test_view.id, COALESCE(test_view.name, t.name),
    test_view.time, test_view.value
  FROM test_view, t WHERE test_view.lag_id = t.id
) SELECT * FROM t ORDER BY id;

这应该要快得多。这个想法来自这篇文章。SQLFiddle:http://sqlfiddle.com/#!15/63f7b/1/1.

票数 1
EN

Stack Overflow用户

发布于 2016-11-26 13:26:49

这对我来说适用于Access 2010:

代码语言:javascript
运行
复制
SELECT 
    t1.id,
    (
        SELECT TOP 1 t2.name
        FROM test t2
        WHERE t2.id<=t1.id AND t2.name IS NOT NULL
        ORDER BY t2.id DESC
    ) AS name,
    t1.time,
    t1.value
FROM test t1

它也可以在其他SQL方言中工作,尽管它们的TOP 1方式可能略有不同(例如,LIMIT 1是一个常见的变体)。

票数 1
EN

Stack Overflow用户

发布于 2016-11-26 10:11:35

您可以通过COALESCE函数和子查询来实现这一点:

代码语言:javascript
运行
复制
SELECT t.id, 
    COALESCE(t.name, (SELECT s.name FROM table s WHERE s.name IS NOT NULL AND s.id < t.id ORDER BY s.id LIMIT 1)) AS name,
    t.time,
    COALESCE(t.value, (SELECT s.value FROM table s WHERE s.value IS NOT NULL AND s.id < t.id ORDER BY s.id LIMIT 1)) AS value
FROM table t ORDER BY t.id
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/40816356

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档