为此,您需要动态 SQL。所以你必须准备好应对可能的 SQL 注入。
基本查询
生成所需 DML 命令的基本查询如下所示:
SELECT format('UPDATE tbl SET (%s) = (%s)'
,string_agg (quote_ident(attname), ', ')
,string_agg ('NULL', ', ')
)
FROM pg_attribute
WHERE attrelid = 'tbl'::regclass
AND NOT attisdropped
AND attnum > 0
AND attname ~~ 'foo_%';
回报:
UPDATE tbl SET (foo_a, foo_b, foo_c) = (NULL, NULL, NULL);
我利用“列列表语法”UPDATE
来缩短代码并简化任务。
我查询系统目录而不是信息模式,因为后者虽然是标准化的并保证可跨主要版本移植,但速度也非常慢,有时也很笨拙。有利有弊,我们在 SO 上已经讨论过好几次了。搜索关键字以获取更多信息。
quote_ident()
对于列名可以防止 SQL 注入,并且对于任何非标准列名也是必需的。
您忽略了提及您的 Postgres 版本。聚合函数string_agg()
需要 9.0+。
具有 PL/pgSQL 功能的完全自动化
CREATE OR REPLACE FUNCTION f_update_cols(_tbl regclass, _col_pattern text
, OUT row_ct int, OUT col_ct int)
RETURNS record AS
$func$
DECLARE
_sql text;
BEGIN
SELECT format('UPDATE tbl SET (%s) = (%s)'
,string_agg (quote_ident(attname), ', ')
,string_agg ('NULL', ', ')
)
,count(*)::int
INTO _sql, col_ct
FROM pg_attribute
WHERE attrelid = _tbl
AND NOT attisdropped -- no dropped columns
AND attnum > 0 -- no system columns
AND attname ~~ _col_pattern; -- only columns matching pattern
-- RAISE NOTICE '%', _sql; -- output generated SQL for debugging
EXECUTE _sql;
GET DIAGNOSTICS row_ct = ROW_COUNT;
END
$func$ LANGUAGE plpgsql;
COMMENT ON FUNCTION f_update_cols(regclass, text)
IS 'Updates all columns of table _tbl ($1)
that match _col_pattern ($2) in a LIKE expression.
Returns the count of columns (col_ct) and rows (row_ct) affected.';
称呼:
SELECT * FROM f_update_cols('myschema.tbl', 'foo%');
-> SQLfiddle 演示。