一尘不染

将整个数据库中的空字符串('')设置为NULL

sql

我的数据库中有许多文本列,其中值是空字符串('')。空字符串需要设置为NULL。我不知道此数据库中的确切架构,表和列,或者我想写一个可以重用的通用解决方案。

我将如何编写查询/函数以在所有架构的所有表中查找所有文本列,并使用空字符串('')将所有列更新为NULL


阅读 380

收藏
2021-03-10

共1个答案

一尘不染

实现此目的的最有效方法:

  • UPDATE每个表运行一个。
  • NOT NULL使用任何实际的空字符串更新可为空的列(未定义)。
  • 仅使用任何实际的空字符串更新行。
  • 保持其他值不变。

这个相关的答案具有plpgsql函数,该函数针对任何给定的表UPDATE使用系统目录pg_attribute自动安全地构建和运行命令

使用f_empty2null()此答案中的函数,您可以像这样遍历选定的表:

DO
$do$
DECLARE
   _tbl regclass;
BEGIN
   FOR _tbl IN
      SELECT c.oid::regclass
      FROM   pg_class c
      JOIN   pg_namespace n ON n.oid = c.relnamespace
      WHERE  c.relkind = 'r'            -- only regular tables
      AND    n.nspname NOT LIKE 'pg_%'  -- exclude system schemas
   LOOP
      RAISE NOTICE $$PERFORM f_empty2null('%');$$, _tbl;
      -- PERFORM f_empty2null(_tbl);  -- uncomment to prime the bomb
   END LOOP;
END
$do$;

小心! 这将更新数据库中所有用户表的所有列中的所有空字符串。确保这是您想要的,否则可能会破坏数据库。

UPDATE当然,您需要对所有选定表具有特权。

作为儿童安全装置,我评论了有效载荷。

重复使用

这是重复使用的集成解决方案。没有安全装置:

CREATE OR REPLACE FUNCTION f_all_empty2null(OUT _tables int, OUT _rows int) AS
$func$
DECLARE
   _typ CONSTANT regtype[] := '{text, bpchar, varchar, \"char\"}';
   _sql text;
   _row_ct int;
BEGIN
   _tables := 0;  _rows := 0;
   FOR _sql IN
      SELECT format('UPDATE %s SET %s WHERE %s'
                  , t.tbl
                  , string_agg(format($$%1$s = NULLIF(%1$s, '')$$, t.col), ', ')
                  , string_agg(t.col || $$ = ''$$, ' OR '))
      FROM  (
         SELECT c.oid::regclass AS tbl, quote_ident(attname) AS col
         FROM   pg_namespace n
         JOIN   pg_class     c ON c.relnamespace = n.oid
         JOIN   pg_attribute a ON a.attrelid = c.oid
         WHERE  n.nspname NOT LIKE 'pg_%'   -- exclude system schemas
         AND    c.relkind = 'r'             -- only regular tables
         AND    a.attnum >= 1               -- exclude tableoid & friends
         AND    NOT a.attisdropped          -- exclude dropped columns
         AND    NOT a.attnotnull            -- exclude columns defined NOT NULL!
         AND    a.atttypid = ANY(_typ)      -- only character types
         ORDER  BY a.attnum
         ) t
      GROUP  BY t.tbl
   LOOP
      EXECUTE _sql;
      GET DIAGNOSTICS _row_ct = ROW_COUNT;  -- report nr. of affected rows
      _tables := _tables + 1;
      _rows := _rows + _row_ct;
   END LOOP;
END
$func$  LANGUAGE plpgsql;

称呼:

SELECT * FROM pg_temp.f_all_empty2null();

返回值:

 _tables | _rows
---------+---------
 23      | 123456

请注意 我如何正确地转义了表名和列名!

c.oid::regclass AS tbl, quote_ident(attname)  AS col
2021-03-10