Atualização de 17/09/2021 :a partir de hoje, gerardnll fornece uma resposta melhor (a melhor IMO) :
Para ajudar as pessoas a encontrar a solução mais limpa, recomendo que você vote na resposta de gerardnll .
(Para sua informação, sou a mesma pessoa que fez a pergunta original.)
Aqui está minha resposta original de 2013
Aqui está uma solução elegante de duas colunas de acordo com a "constraint -- one ou a outra coluna não é nula" quadro de mensagens do PostgreSQL :
ALTER TABLE my_table ADD CONSTRAINT my_constraint CHECK (
(column_1 IS NULL) != (column_2 IS NULL));
(Mas a abordagem acima não é generalizável para três ou mais colunas.)
Se você tiver três ou mais colunas, poderá usar a abordagem da tabela verdade ilustrada por a_horse_with_no_name . No entanto, considero o seguinte mais fácil de manter porque você não precisa digitar as combinações 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 isso, seria útil criar uma função personalizada para que o
CASE WHEN column_k IS NULL THEN 0 ELSE 1 END
clichê pode ser removido, deixando algo como:(non_null_count(column_1) +
non_null_count(column_2) +
non_null_count(column_3)) = 1
Isso pode ser tão compacto quanto o PSQL permitirá (?). Dito isso, prefiro chegar a esse tipo de sintaxe, se possível:
non_null_count(column_1, column_2, column_3) = 1