Actualización del 17 de septiembre de 2021 :A partir de hoy, gerardnll proporciona una mejor respuesta (la mejor IMO) :
Para ayudar a las personas a encontrar la solución más limpia, le recomiendo que vote a favor respuesta de gerardnll .
(Para tu información, soy la misma persona que hizo la pregunta original).
Esta es mi respuesta original de 2013
Aquí hay una solución elegante de dos columnas según la restricción " -- uno o la otra columna no es nula" Tablero de mensajes de PostgreSQL :
ALTER TABLE my_table ADD CONSTRAINT my_constraint CHECK (
(column_1 IS NULL) != (column_2 IS NULL));
(Pero el enfoque anterior no se puede generalizar a tres o más columnas).
Si tiene tres o más columnas, puede usar el enfoque de la tabla de verdad ilustrado por a_horse_with_no_name . Sin embargo, considero que lo siguiente es más fácil de mantener porque no tiene que escribir las combinaciones lógicas:
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;
Para compactar esto, sería útil crear una función personalizada para que CASE WHEN column_k IS NULL THEN 0 ELSE 1 END
se podría quitar el texto repetitivo, dejando algo como:
(non_null_count(column_1) +
non_null_count(column_2) +
non_null_count(column_3)) = 1
Eso puede ser tan compacto como lo permita PSQL (?). Dicho esto, preferiría llegar a este tipo de sintaxis si es posible:
non_null_count(column_1, column_2, column_3) = 1