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

Set empty strings ('') to NULL in the whole database

在我的数据库中有许多值为空字符串的文本列 ('')。空字符串需要设置为 NULL。我不知道这个数据库中的确切模式、表和列,或者我想编写一个可以重复使用的通用解决方案。

我将如何编写查询/函数来查找所有模式中所有表中的所有文本列并将所有包含空字符串 ('') 的列更新为 NULL

最简单的方法是手动,table table。对于每个 table,做这样的事情:

START TRANSACTION;
UPDATE tablename SET 
    stringfield1 = NULLIF(stringfield1, ''),
    stringfield2 = NULLIF(stringfield2, '');
<do some selects to make sure everything looks right>
COMMIT;

这将重写 table 中的每一行,但它只会在 table 上传递一次。这对您来说可能不切实际。

您可能希望使用 WHERE 子句逐个字段执行此操作,以减少更新次数,就像这样。

START TRANSACTION;
UPDATE tablename SET stringfield1 = NULL WHERE stringfield1 = '';
<do some selects to make sure everything looks right>
COMMIT;

这只会重写需要重写的行,但每个 table 都需要多次传递。

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

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

这个相关的答案有一个 plpgsql 函数,它使用系统目录 pg_attribute 为任何给定的 table:

自动安全地构建和运行 UPDATE 命令
  • Replace empty strings with null values

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

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$;

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

当然,您需要对所有选定的 table 拥有 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();

Returns:

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

注意 我是如何正确转义 table 和列名的!

c.oid::regclass AS tbl, quote_ident(attname)  AS col

考虑:

  • Table name as a PostgreSQL function parameter

小心! 警告同上。
还要考虑我上面链接的答案中的基本解释:

  • Replace empty strings with null values

我认为下面的代码是通用的。你可以随时随地使用它:

    Declare @Query varchar(1000)
    declare @AllDatabaseTables table(id int,Table_Name varchar(50))
    Insert into @AllDatabaseTables select Table_Name from information_schema.tables

    declare @Table_Name varchar(50)

    declare @i int=1
    While @i<=(Select Count(*) from @AllDatabaseTables)
    BEGIN
    Select @Table_Name=Table_Name from @AllDatabaseTables Where id=@i

    Declare @ColumnTable table(id int,ColumnName varchar(100))
    Insert into @ColumnTable Select COLUMN_NAME from information_schema.columns Where Table_Name=@Table_Name and DATA_TYPE='varchar' --if the datatype is varchar type
    Declare @ColumnName varchar(50)
    Declare @k int=1
    While @k<=(Select count(*) from @ColumnTable)
        BEGIN
            Select @ColumnName=ColumnName from @ColumnTable where id=@k

            Set @Query='Update '+@Table_Name+' Set '+@ColumnName+'=NULL where '+@ColumnName+'='''' ' 
            Exec(Query)

            Set @k=@k+1
        END



    Set @i=@i+1

END