Vous avez besoin de SQL dynamique pour cela. Vous devez donc être prêt à faire face à une éventuelle injection SQL.
Requête de base
La requête de base pour générer la commande DML nécessaire peut ressembler à ceci :
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_%';
Renvoie :
UPDATE tbl SET (foo_a, foo_b, foo_c) = (NULL, NULL, NULL);
-
J'utilise la "syntaxe de liste de colonnes " de
UPDATE
pour raccourcir le code et simplifier la tâche. -
J'interroge les catalogues système au lieu de schéma d'information car ce dernier, tout en étant standardisé et garanti portable sur toutes les versions majeures, est également notoirement lent et parfois peu maniable. Il y a des avantages et des inconvénients, nous en avons discuté plusieurs fois ici sur SO. Recherchez les mots-clés pour plus d'informations.
-
quote_ident()
pour les noms de colonnes empêche l'injection SQL et est également nécessaire pour tous noms de colonnes non standard. -
Vous avez omis de mentionner votre version de Postgres. La fonction d'agrégation
string_agg()
nécessite 9.0+.
Automatisation complète avec la fonction 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.';
Appel :
SELECT * FROM f_update_cols('myschema.tbl', 'foo%');
-
Pour rendre la fonction plus pratique, elle renvoie des informations comme décrit dans le commentaire. En savoir plus sur l'obtention du statut du résultat dans plpgsql dans le manuel.
-
J'utilise la variable
_sql
pour contenir la chaîne de requête, afin que je puisse collecter le nombre de colonnes trouvées (col_ct
) dans la même requête. -
Le type d'identifiant d'objet
regclass
est le moyen le plus efficace d'éviter automatiquement l'injection SQL (et de nettoyer les noms non standard) pour le nom de la table également. Vous pouvez utiliser des noms de table qualifiés par le schéma pour éviter les ambiguïtés. Je vous conseillerais de le faire si vous avez plusieurs schémas dans votre base de données ! Plus de détails dans cette question connexe :
Nom de table en tant que paramètre de fonction PostgreSQL