在表的所有列中将'n / a'替换为'NA'

时间:2016-08-04 20:46:38

标签: sql postgresql sql-update dynamic-sql psql

如何更新PostgreSQL中表的所有列?而不是一次只做一列 鉴于此表:

Table1
Field1 | Field 2 | Field 3
123    | 987     | n/a
456    | n/a     | 101
n/a    | abcdef  | n/a

结果应为:

Table1
Field1 | Field 2 | Field 3
123    | 987     | NA
456    | NA      | 101
NA     | abcdef  | NA

我正在寻找 SQL查询。

1 个答案:

答案 0 :(得分:0)

您可以从UPDATE语句或plpgsql函数中的系统目录中动态构建DO命令:

CREATE OR REPLACE FUNCTION f_global_replace(_tbl regclass
                                          , _old text
                                          , _new text
                                          , OUT updated_rows int) AS
$func$
DECLARE
   -- basic char types, possibly extend with citext, domains or custom types:
   _typ  CONSTANT regtype[] := '{text, bpchar, varchar}';
   _sql  text;
BEGIN
   SELECT INTO _sql     -- build command
          format('UPDATE %s SET %s WHERE $1 IN (%s)'
               , _tbl
               , string_agg(format('%1$s = CASE WHEN %1$s = $1 THEN $2 ELSE %1$s END', col), ', ')
               , string_agg(col, ','))
   FROM  (
      SELECT quote_ident(attname) AS col  -- escape names, prevent SQL injection!
      FROM   pg_attribute
      WHERE  attrelid = _tbl              -- valid, visible, legal table name 
      AND    attnum >= 1                  -- exclude tableoid & friends
      AND    NOT attisdropped             -- exclude dropped columns
      AND    atttypid = ANY(_typ)         -- only character types
      ORDER  BY attnum
      ) sub;

   -- RAISE NOTICE '%', _sql;             -- debug

   IF _sql IS NULL THEN
      updated_rows := 0;                         -- nothing to update
   ELSE
      EXECUTE _sql USING _old, _new;
      GET DIAGNOSTICS updated_rows = ROW_COUNT;  -- Report number of affected rows
   END IF;
END
$func$  LANGUAGE plpgsql;

这会组装并自动执行以下形式的查询:

UPDATE table1
SET    field1 = CASE WHEN field1 = $1 THEN $2 ELSE field1 END
     , field2 = CASE WHEN field2 = $1 THEN $2 ELSE field2 END
     , field3 = CASE WHEN field3 = $1 THEN $2 ELSE field3 END
WHERE  $1 IN (field1,field2,field3);

小心! 该功能会更新所有字符类型列。确保它按预期工作。为了安全起见,我建议在显式事务中运行它,并且只在检查后提交:

BEGIN;
SELECT * FROM f_global_replace('table1'::regclass, 'n/a', 'NA');

TABLE table1;  -- all good?

COMMIT;  -- then commit; else ROLLBACK;

相关答案以及更多信息和链接: