Mise à jour du 17/09/2021 :À ce jour, gerardnll fournit une meilleure réponse (la meilleure IMO) :
Afin d'aider les gens à trouver la solution la plus propre, je vous recommande de voter pour la réponse de gerardnll .
(Pour votre information, je suis la même personne qui a posé la question initiale.)
Voici ma réponse originale de 2013
Voici une solution élégante à deux colonnes selon la "contrainte -- une ou l'autre colonne non nulle" Message Board PostgreSQL :
ALTER TABLE my_table ADD CONSTRAINT my_constraint CHECK (
(column_1 IS NULL) != (column_2 IS NULL));
(Mais l'approche ci-dessus n'est pas généralisable à trois colonnes ou plus.)
Si vous avez trois colonnes ou plus, vous pouvez utiliser l'approche de la table de vérité illustrée par a_horse_with_no_name . Cependant, je considère que les éléments suivants sont plus faciles à gérer car vous n'avez pas à saisir les combinaisons logiques :
ALTER TABLE my_table
ADD CONSTRAINT my_constraint CHECK (
(CASE WHEN column_1 IS NULL THEN 0 ELSE 1 END) +
(CASE WHEN column_2 IS NULL THEN 0 ELSE 1 END) +
(CASE WHEN column_3 IS NULL THEN 0 ELSE 1 END) = 1;
Pour compacter cela, il serait utile de créer une fonction personnalisée afin que le CASE WHEN column_k IS NULL THEN 0 ELSE 1 END
le passe-partout pourrait être supprimé, laissant quelque chose comme :
(non_null_count(column_1) +
non_null_count(column_2) +
non_null_count(column_3)) = 1
Cela peut être aussi compact que PSQL le permettra (?). Cela dit, je préférerais arriver à ce genre de syntaxe si possible :
non_null_count(column_1, column_2, column_3) = 1