Est-il possible de façon dynamique une boucle à travers les colonnes d'une table?
-
28-09-2019 - |
Question
J'ai une fonction de déclenchement pour un test de table qui a le code suivant:
IF TG_OP='UPDATE' THEN
IF OLD.locked > 0 AND
( OLD.org_id <> NEW.org_id OR
OLD.document_code <> NEW.document_code OR
-- other columns ...
)
THEN
RAISE EXCEPTION 'Message';
-- more code
Je vérifie statiquement toute nouvelle valeur de la colonne avec sa valeur précédente pour assurer l'intégrité. Maintenant, chaque fois que mes changements de logique métier et je dois ajouter de nouvelles colonnes dans cette table, je vais devoir modifier ce déclencheur chaque fois. Je pensais que ce serait mieux si je pouvais en quelque sorte dynamiquement vérifier toutes les colonnes de cette table, sans taper explicitement leur nom.
Comment peut-il être fait?
La solution
Jetez un oeil à la information_schema, il y a une vue « colonnes ». Exécuter une requête pour obtenir tous les columnNames actuels de la table qui a tiré sur la gâchette:
SELECT
column_name
FROM
information_schema.columns
WHERE
table_schema = TG_TABLE_SCHEMA
AND
table_name = TG_TABLE_NAME;
Boucle par le résultat et là vous allez!
Plus d'informations peuvent être trouvées dans le fin manuel.
Autres conseils
A partir de la documentation 9.0 beta2 au sujet de la clause de WHEN
dans les déclencheurs, ce qui pourrait être en mesure d'être utilisé dans les versions antérieures dans le corps de déclenchement:
OLD.* IS DISTINCT FROM NEW.*
ou peut-être ( de notes de version 8.2 )
IF row(new.*) IS DISTINCT FROM row(old.*)
Utilisez pl / perl ou pl / python. Ils sont beaucoup mieux adaptés à ces tâches. beaucoup mieux.
Vous pouvez également installer hstore nouvelle , et de l'utiliser de ligne-> hstore sémantique , mais c'est certainement pas une bonne idée lors de l'utilisation normale des types de données.
Dans Postgres 9.0 ou version ultérieure ajouter un clause WHEN
votre définition de déclenchement (déclaration de CREATE TRIGGER
):
CREATE TRIGGER foo
BEFORE UPDATE
FOR EACH ROW
WHEN (OLD IS DISTINCT FROM NEW) -- parentheses required!
EXECUTE PROCEDURE ...;
Uniquement possible pour les déclencheurs BEFORE
/ AFTER
UPDATE
, où sont définies à la fois OLD
et NEW
. Vous obtiendrez une exception en essayant d'utiliser cette clause WHEN
avec des déclencheurs de INSERT
ou DELETE
.
Et simplifier radicalement la détente fonction en conséquence:
...
IF OLD.locked > 0 THEN
RAISE EXCEPTION 'Message';
END IF;
...
Pas besoin de IF TG_OP='UPDATE' ...
test car ce déclencheur ne fonctionne que pour UPDATE
de toute façon.
Ou déplacer cette condition dans la clause WHEN aussi:
CREATE TRIGGER foo
BEFORE UPDATE
FOR EACH ROW
WHEN (OLD.locked > 0
AND OLD IS DISTINCT FROM NEW)
EXECUTE PROCEDURE ...;
ne laissant qu'une RAISE EXCEPTION
inconditionnelle dans votre fonction de déclenchement, qui est appelé uniquement en cas de besoin pour commencer.
Dans un déclencheur
BEFORE
, la condition deWHEN
est évaluée juste avant la fonction est ou serait exécuté, donc l'utilisationWHEN
est pas matériellement différent de tester le même état au début de la fonction déclencheur. Note en particulier que la ligne deNEW
vu par la condition est la valeur actuelle, comme précédemment éventuellement modifié par déclencheurs. En outre, un état deBEFORE
de déclenchementWHEN
ne peut pas examiner les colonnes du système de la rangée deNEW
(commeoid
), car celles n'aura pas encore été fixée.Dans un déclencheur
AFTER
, la condition deWHEN
est évaluée juste après la mise à jour de ligne se produit, et il détermine si un événement est mis en attente à feu sur la gâchette à la fin de l'instruction. Alors, quand un de déclencheur deAFTER
conditionWHEN
ne retourne pas vrai, il ne faut pas faire la queue d'un événement, ni pour récupérer à la ligne à la fin de la déclaration. Cela peut entraîner speedups importantes dans les déclarations qui modifient de lignes, si le déclencheur ne doit être tiré pour quelques lignes.
Related:
Pour répondre aussi le titre de la question
Est-il possible de boucle de manière dynamique à travers les colonnes d'une table?
Oui. Exemples: