Du skal bruge dynamisk SQL til dette. Så du skal være forberedt på at håndtere eventuel SQL-injektion.
Grundlæggende forespørgsel
Den grundlæggende forespørgsel til at generere den nødvendige DML-kommando kan se sådan ud:
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_%';
Returnerer:
UPDATE tbl SET (foo_a, foo_b, foo_c) = (NULL, NULL, NULL);
-
Jeg gør brug af "kolonnelistesyntaks stærk> " af
UPDATE
for at forkorte koden og forenkle opgaven. -
Jeg forespørger på systemkatalogerne i stedet for informationsskema fordi sidstnævnte, selv om det er standardiseret og garanteret at være bærbart på tværs af større versioner, også er notorisk langsom og nogle gange uhåndterligt. Der er fordele og ulemper, det har vi diskuteret flere gange her på SO. Søg efter nøgleordene for at få flere oplysninger.
-
quote_ident()
for kolonnenavnene forhindrer SQL-injektion og er også nødvendig for enhver ikke-standard kolonnenavne. -
Du forsømte at nævne din Postgres-version. Den samlede funktion
string_agg()
kræver 9.0+.
Fuld automatisering 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 til:
SELECT * FROM f_update_cols('myschema.tbl', 'foo%');
-
For at gøre funktionen mere praktisk returnerer den information som beskrevet i kommentaren. Mere om opnåelse af resultatstatus i plpgsql i manualen.
-
Jeg bruger variablen
_sql
at holde forespørgselsstrengen, så jeg kan indsamle antallet af fundne kolonner (col_ct
) i samme forespørgsel. -
Objektidentifikatortypen
regclass
er den mest effektive måde til automatisk at undgå SQL-injektion (og rense ikke-standardnavne) for tabelnavnet. Du kan bruge skema-kvalificerede tabelnavne for at undgå uklarheder. Jeg vil råde dig til at gøre det, hvis du har flere skemaer i din db! Flere detaljer i dette relaterede spørgsmål:
Tabelnavn som en PostgreSQL-funktionsparameter