我正在按计数将一个巨大的表卷成一个新表,我想在其中将所有空字符串更改为NULL
,并对一些列进行类型转换。我通读了一些帖子,但找不到查询,这可以让我在单个查询中跨所有列执行此操作,而无需使用多个语句。
让我知道我是否可以遍历所有列并将单元格替换为空字符串和 null。
我正在按计数将一个巨大的表卷成一个新表,我想在其中将所有空字符串更改为NULL
,并对一些列进行类型转换。我通读了一些帖子,但找不到查询,这可以让我在单个查询中跨所有列执行此操作,而无需使用多个语句。
让我知道我是否可以遍历所有列并将单元格替换为空字符串和 null。
据我所知,没有内置函数可以替换表的所有列中的空字符串。您可以编写一个plpgsql 函数来处理它。
以下函数将给定表的所有基本字符类型列中的空字符串替换为NULL
. integer
如果剩余的字符串是有效的数字文字,则可以转换为。
CREATE OR REPLACE FUNCTION f_empty_text_to_null(_tbl regclass, OUT updated_rows int)
LANGUAGE plpgsql AS
$func$
DECLARE
_typ CONSTANT regtype[] := '{text, bpchar, varchar}'; -- ARRAY of all basic character types
_sql text;
BEGIN
SELECT INTO _sql -- build SQL command
'UPDATE ' || _tbl
|| E'\nSET ' || string_agg(format('%1$s = NULLIF(%1$s, '''')', col), E'\n ,')
|| E'\nWHERE ' || 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;
-- RAISE NOTICE '%', _sql; -- test?
-- 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$;
称呼:
SELECT f_empty2null('mytable');
SELECT f_empty2null('myschema.mytable');
还要获取列名updated_rows
:
SELECT * FROM f_empty2null('mytable');
表名必须有效且可见,调用用户必须拥有所有必要的权限。如果不满足这些条件中的任何一个,该函数将不执行任何操作——即也不会破坏任何内容。我强制转换为对象标识符类型regclass
以确保它。
表名可以按原样 ( 'mytable'
) 提供,然后由search_path
决定。或模式限定以选择特定模式 ( 'myschema.mytable'
)。
查询系统目录以获取表的所有(字符类型)列。提供的函数使用这些基本字符类型:text
, bpchar
, varchar
, "char"
. 仅处理相关列。
使用quote_ident()
或format()
清理列名并防范 SQLi。
更新版本使用基本的 SQL 聚合函数string_agg()
来构建命令字符串,无需循环,更简单、更快捷。而且更优雅。:)
必须将动态 SQL 与EXECUTE
.
更新后的版本不包括已定义的列,并且仅在单个语句中NOT NULL
更新每一行一次,这对于具有多个字符类型列的表来说要快得多。
应该适用于任何现代版本的 PostgreSQL。使用 Postgres 9.1、9.3、9.5 和 13 进行测试。