Hiervoor heb je dynamische SQL nodig. U moet dus voorbereid zijn op mogelijke SQL-injectie.
Basisquery
De basisquery om het benodigde DML-commando te genereren kan er als volgt uitzien:
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_%';
Retourneren:
UPDATE tbl SET (foo_a, foo_b, foo_c) = (NULL, NULL, NULL);
-
Ik gebruik de "kolomlijstsyntaxis " van
UPDATE
om de code in te korten en de taak te vereenvoudigen. -
Ik zoek de systeemcatalogi in plaats van informatieschema omdat de laatste, hoewel gestandaardiseerd en gegarandeerd draagbaar in de belangrijkste versies, ook notoir traag en soms onpraktisch is. Er zijn voor- en nadelen, we hebben dit hier op SO al meerdere keren besproken. Zoek naar de trefwoorden voor meer informatie.
-
quote_ident()
voor de kolomnamen voorkomt SQL-injectie en is ook nodig voor elke niet-standaard kolomnamen. -
U heeft verzuimd uw Postgres-versie te vermelden. De verzamelfunctie
string_agg()
vereist 9.0+.
Volledige automatisering met PL/pgSQL-functie
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.';
Bel:
SELECT * FROM f_update_cols('myschema.tbl', 'foo%');
-
Om de functie praktischer te maken, retourneert het informatie zoals beschreven in de opmerking. Meer over het verkrijgen van de resultaatstatus in plpgsql in de handleiding.
-
Ik gebruik de variabele
_sql
om de queryreeks vast te houden, zodat ik het aantal gevonden kolommen kan verzamelen (col_ct
) in dezelfde zoekopdracht. -
Het object-ID type
regclass
is de meest efficiënte manier om automatisch SQL-injectie te vermijden (en ook niet-standaardnamen te zuiveren) voor de tabelnaam. U kunt schema-gekwalificeerde tabelnamen . gebruiken onduidelijkheden te voorkomen. Ik zou adviseren om dit te doen als je meerdere schema's in je db hebt! Meer details in deze gerelateerde vraag:
Tabelnaam als een PostgreSQL-functieparameter