Du behöver dynamisk SQL för detta. Så du måste vara beredd att hantera eventuell SQL-injektion.
Grundläggande fråga
Den grundläggande frågan för att generera DML-kommandot som behövs kan se ut så här:
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_%';
Returnerar:
UPDATE tbl SET (foo_a, foo_b, foo_c) = (NULL, NULL, NULL);
-
Jag använder mig av "kolumnlistsyntax stark> " av
UPDATE
för att förkorta koden och förenkla uppgiften. -
Jag frågar systemkatalogerna istället för informationsschema eftersom den senare, samtidigt som den är standardiserad och garanterad att vara bärbar över större versioner, också är notoriskt långsam och ibland svårhanterlig. Det finns för- och nackdelar, vi har diskuterat detta flera gånger här på SO. Sök efter nyckelorden för mer information.
-
quote_ident()
för kolumnnamnen förhindrar SQL-injektion och är också nödvändig för alla icke-standardiserade kolumnnamn. -
Du försummade att nämna din Postgres-version. Den aggregerade funktionen
string_agg()
kräver 9.0+.
Fullautomatisering med PL/pgSQL-funktion
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.';
Ring:
SELECT * FROM f_update_cols('myschema.tbl', 'foo%');
-
För att göra funktionen mer praktisk returnerar den information som beskrivs i kommentaren. Mer om att få resultatstatus i plpgsql i manualen.
-
Jag använder variabeln
_sql
för att hålla frågesträngen, så att jag kan samla antalet kolumner som hittats (col_ct
) i samma fråga. -
Objektidentifieraren typ
regclass
är det mest effektiva sättet att automatiskt undvika SQL-injektion (och sanera icke-standardiserade namn) för tabellnamnet också. Du kan använda schemakvalificerade tabellnamn för att undvika oklarheter. Jag skulle råda dig att göra det om du har flera scheman i din db! Mer information i den här relaterade frågan:
Tabellnamn som en PostgreSQL-funktionsparameter