Postgres a-t-il un moyen de dire ALTER TABLE foo ADD CONSTRAINT bar ...
qui ignorera simplement la commande si la contrainte existe déjà, afin qu'elle ne déclenche pas d'erreur?
Cela pourrait aider, même si cela peut être un peu un hack sale:
create or replace function create_constraint_if_not_exists (
t_name text, c_name text, constraint_sql text
)
returns void AS
$$
begin
-- Look for our constraint
if not exists (select constraint_name
from information_schema.constraint_column_usage
where table_name = t_name and constraint_name = c_name) then
execute constraint_sql;
end if;
end;
$$ language 'plpgsql'
Appelez ensuite avec:
SELECT create_constraint_if_not_exists(
'foo',
'bar',
'ALTER TABLE foo ADD CONSTRAINT bar CHECK (foobies < 100);')
Mise à jour:
Selon réponse de Webmut ci-dessous, suggérant:
ALTER TABLE foo DROP CONSTRAINT IF EXISTS bar;
ALTER TABLE foo ADD CONSTRAINT bar ...;
C'est probablement bien dans votre base de données de développement, ou là où vous savez que vous pouvez fermer les applications qui dépendent de cette base de données pour une fenêtre de maintenance.
Mais s'il s'agit d'un environnement de production 24h/24 et 7j/7, vous ne voulez pas vraiment laisser tomber les contraintes comme ça. Même pendant quelques millisecondes, il y a une courte fenêtre où vous n'appliquez plus votre contrainte, ce qui peut permettre aux valeurs errantes de passer. Cela peut avoir des conséquences inattendues entraînant des coûts commerciaux considérables à un moment donné.
Une solution possible consiste à simplement utiliser DROP IF EXISTS avant de créer la nouvelle contrainte.
ALTER TABLE foo DROP CONSTRAINT IF EXISTS bar;
ALTER TABLE foo ADD CONSTRAINT bar ...;
Semble plus facile que d'essayer d'interroger le schéma_information ou les catalogues, mais peut être lent sur les tables énormes car il recrée toujours la contrainte.
Edit 2015-07-13: Kev a souligné dans sa réponse que ma solution crée une courte fenêtre lorsque la contrainte n'existe pas et n'est pas appliquée. Bien que cela soit vrai, vous pouvez éviter une telle fenêtre assez facilement en encapsulant les deux instructions dans une transaction.
Vous pouvez utiliser un gestionnaire d'exceptions à l'intérieur d'un bloc DO anonyme pour intercepter l'erreur d'objet en double.
DO $$
BEGIN
BEGIN
ALTER TABLE foo ADD CONSTRAINT bar ... ;
EXCEPTION
WHEN duplicate_object THEN RAISE NOTICE 'Table constraint foo.bar already exists';
END;
END $$;
http://www.postgresql.org/docs/9.4/static/sql-do.htmlhttp://www.postgresql.org/docs/9.4/static/plpgsql- control-structures.htmlhttp://www.postgresql.org/docs/9.4/static/errcodes-appendix.html
vous pouvez exécuter la requête sur pg_constraint
une table pour trouver la contrainte existe ou non.
SELECT 1 FROM pg_constraint WHERE conname = 'constraint_name'"
La création de contraintes peut être une opération coûteuse sur une table contenant beaucoup de données, je vous recommande donc de ne pas supprimer les contraintes uniquement pour les recréer immédiatement immédiatement après - vous ne voulez créer cette chose qu'une seule fois.
J'ai choisi de résoudre ce problème en utilisant un bloc de code anonyme, très similaire à Mike Stankavich, mais contrairement à Mike (qui détecte une erreur), je vérifie d'abord si la contrainte existe:
DO $$
BEGIN
IF NOT EXISTS ( SELECT constraint_schema
, constraint_name
FROM information_schema.check_constraints
WHERE constraint_schema = 'myschema'
AND constraint_name = 'myconstraintname'
)
THEN
ALTER TABLE myschema.mytable ADD CONSTRAINT myconstraintname CHECK (column <= 100);
END IF;
END$$;