用空值替换空字符串

Vij*_* DJ 4 string postgresql null replace plpgsql

我正在将一个庞大的表按计数汇总到一个新表中,在该表中我想将所有空字符串更改为NULL,并同时对一些列进行类型转换。我通读了一些帖子,但找不到查询,这使我可以在单个查询中跨所有列进行查询,而无需使用多个语句。

让我知道是否可以遍历所有列,并将单元格替换为具有null的空字符串。

参考:如何使用SQL Server将空格转换为空值?

Erw*_*ter 5

据我所知,没有内置函数可以替换表中所有列的空字符串。您可以编写一个plpgsql函数来解决这个问题。

下面的函数替换空字符串在一个给定表的所有基本字符类型的列NULL。然后,integer如果其余字符串是有效的数字文字,则可以强制转换为。

CREATE OR REPLACE FUNCTION f_empty2null(_tbl regclass, OUT updated_rows int) AS
$func$
DECLARE
   -- basic char types, possibly extend with citext, domains or custom types:
   _typ  CONSTANT regtype[] := '{text, bpchar, varchar, \"char\"}';
   _sql  text;
BEGIN
   SELECT INTO _sql     -- build command
          format('UPDATE %s SET %s WHERE %s'
               , _tbl
               , string_agg(format($$%1$s = NULLIF(%1$s, '')$$, col), ', ')
               , string_agg(col || $$ = ''$$, ' OR '))
   FROM  (
      SELECT quote_ident(attname) AS col
      FROM   pg_attribute
      WHERE  attrelid = _tbl              -- valid, visible, legal table name 
      AND    attnum >= 1                  -- exclude tableoid & friends
      AND    NOT attisdropped             -- exclude dropped columns
      AND    NOT attnotnull               -- exclude columns defined NOT NULL!
      AND    atttypid = ANY(_typ)         -- only character types
      ORDER  BY attnum
      ) sub;

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

   -- Execute
   IF _sql IS NULL THEN
      updated_rows := 0;                         -- nothing to update
   ELSE
      EXECUTE _sql;
      GET DIAGNOSTICS updated_rows = ROW_COUNT;  -- Report number of affected rows
   END IF;
END
$func$  LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)

呼叫:

SELECT f_empty2null('mytable');
SELECT f_empty2null('myschema.mytable');
Run Code Online (Sandbox Code Playgroud)

同样要获取列名updated_rows

SELECT * FROM f_empty2null('mytable');
Run Code Online (Sandbox Code Playgroud)

SQL提琴。

要点

  • 表名必须有效且可见,并且调用用户必须具有所有必要的特权。如果不满足这些条件中的任何一个,则该函数将不执行任何操作-即,也不会破坏任何操作。我强制转换为对象标识符类型regclass以确保其正确性。
    可以按原样提供表名'mytable',然后search_path确定。或符合模式资格以选择特定模式('myschema.mytable')。

  • 查询系统目录以获取表的所有(字符类型)列。所提供的功能,使用这些基本字符类型textbpcharvarchar"char"。仅处理相关列。

  • 使用quote_ident()清除format()列名并防止SQLi

  • 更新的版本使用基本的SQL聚合函数string_agg()来构建命令字符串而无需循环,这更加简单和快捷。而且更优雅。:)

  • 必须在中使用动态SQLEXECUTE

  • 更新的版本不包括定义的列,NOT NULL并且仅在单个语句中更新每行一次,这对于具有多个字符类型列的表来说要快得多。

  • 应该适用于任何现代版本的PostgreSQL。使用Postgres 9.1、9.3和9.5测试。