2

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

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

编辑:一个警告是我将 postgresql 8.4 与 Greenplum 一起使用,因此不支持相关子查询。

4

3 回答 3

3
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 存在多个名称,则此查询将失败。(并且它不会触及不存在非空名称的记录)

如果您使用的 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;
于 2012-07-21T11:51:56.473 回答
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

于 2012-07-21T18:26:14.807 回答
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;
于 2012-07-21T04:07:47.347 回答