在我的数据库中有许多文本列,其中的值是空字符串 (''
)。空字符串需要设置为NULL
。我不知道这个数据库中的确切模式、表和列,或者我想编写一个可以重复使用的通用解决方案。
我将如何编写查询/函数来查找所有模式中所有表中的所有文本列并将所有包含空字符串 (''
) 的列更新为 NULL
?
最佳答案
最有效的方法是:
- 为每个表运行一个
UPDATE
。 - 仅使用任何实际的空字符串更新可为空的列(未定义
NOT NULL
)。 - 仅更新包含任何实际空字符串的行。
- 保留其他值不变。
这个相关的答案有一个 plpgsql 函数,它使用系统目录 pg_attribute
为任何给定的表自动安全地构建和运行 UPDATE
命令:
使用此答案中的函数 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
权限。
作为 child 安全装置,我评论了有效载荷。
您可能已经注意到我直接使用系统目录,而不是信息模式(这也可以)。关于这个:
- How to check if a table exists in a given schema
- Query to return output column names and data types of a query, table or view
重复使用
这是一个可重复使用的集成解决方案。无安全装置:
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
考虑:
小心!与上述警告相同。
还要考虑我上面链接的答案中的基本解释:
关于sql - 在整个数据库中将空字符串 ('' ) 设置为 NULL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38459106/