在postgresql中,如何在列中填写缺失值?

时间:2012-07-21 03:57:45

标签: sql greenplum

我正在尝试弄清楚如何使用来自给定列上具有相同值的其他行的非缺失值来填充一列中缺少的值。例如,在下面的示例中,我希望所有“1”值等于Bob,并且所有“2”值都等于John

ID #   | Name
-------|-----
1      | Bob 
1      | (null)
1      | (null)
2      | John
2      | (null)
2      | (null)
`

编辑:有一点需要注意,我正在使用带有Greenplum的postgresql 8.4,因此不支持相关的子查询。

3 个答案:

答案 0 :(得分:2)

CREATE TABLE bobjohn
        ( ID INTEGER NOT NULL
        , zname varchar
        );
INSERT INTO bobjohn(id, zname) VALUES
 (1,'Bob') ,(1, NULL) ,(1, NULL)
,(2,'John') ,(2, NULL) ,(2, NULL)
        ;

UPDATE bobjohn dst
SET zname = src.zname
FROM bobjohn src
WHERE dst.id = src.id
AND dst.zname IS NULL
AND src.zname IS NOT NULL
        ;

SELECT * FROM bobjohn;

注意:如果给定Id存在多个名称,则此查询将失败。 (并且它不会触及 no 非空名称存在的记录)

如果您使用的是postgres版本> -9,则可以使用CTE来获取源元组(这相当于子查询,但更容易编写和读取(恕我直言).CTE也处理重复价值问题(以相当粗略的方式):

        --
        -- CTE's dont work in update queries for Postgres version below 9
        --
WITH uniq AS (
        SELECT DISTINCT id
        -- if there are more than one names for a given Id: pick the lowest
        , min(zname) as zname
        FROM bobjohn
        WHERE zname IS NOT NULL
        GROUP BY id
        )
UPDATE bobjohn dst
SET zname = src.zname
FROM uniq src
WHERE dst.id = src.id
AND dst.zname IS NULL
        ;

SELECT * FROM bobjohn;

答案 1 :(得分:1)

UPDATE tbl
SET    name = x.name
FROM  (
    SELECT DISTINCT ON (id) id, name
    FROM   tbl
    WHERE  name IS NOT NULL
    ORDER  BY id, name
    ) x
WHERE  x.id = tbl.id
AND    tbl.name IS NULL;

DISTINCT ON独自完成工作。不需要额外的聚合。

如果name有多个值,则会选择按字母顺序排列的第一个(根据当前区域设置) - 这就是ORDER BY id, name的用途。如果name明确无误,则可以省略该行。

此外,如果每个id至少有一个非空值,则可以省略WHERE name IS NOT NULL

答案 2 :(得分:0)

如果您知道的事实没有冲突的值(多个行具有相同的ID但不同的非空名称),那么这样的内容将适当地更新表:

UPDATE some_table AS t1
SET name = (
    SELECT name
    FROM some_table AS t2
    WHERE t1.id = t2.id
      AND name IS NOT NULL
    LIMIT 1
)
WHERE name IS NULL;

如果您只想查询表并动态填写此信息,则可以使用类似的查询:

SELECT
    t1.id,
    (
        SELECT name
        FROM some_table AS t2
        WHERE t1.id = t2.id
          AND name IS NOT NULL
        LIMIT 1
    ) AS name

FROM some_table AS t1;