Is it possible to make a XOR CHECK CONSTRAINT?
I'm doing it on a test table I just made that is called test and has 3 columns:
I made a check constraint for this:
(a IS NOT NULL AND b = NULL) OR (b IS NOT NULL AND a = NULL)
Which apparently would work in MSSQL
I tested it by doing this:
INSERT INTO public.test(
id, a, b)
VALUES (1, 1, 1);
Which should fail, seeing as it doesn't evaluate to TRUE on either side of the OR. However, it's inserting just fine.
When I look at what postgres actually stored as constraint I get this:
(a IS NOT NULL AND b = NULL::bigint OR b IS NOT NULL AND a = NULL::bigint)
I heard AND takes precedent over OR so even this should still work.
Does anyone have a solution for this? Preferably one that is also possible with three or more columns? I understand that those might be more complicated though.
EDIT: Changing
= NULL
to
IS NULL
give me:
ERROR: cannot cast type boolean to bigint
Right, the a = NULL
and b = NULL
bit was the issue as @a_horse_with_no_name indicated. You might also consider this derivative, which doesn't require the OR
operator:
create table test
(
id integer primary key,
a integer,
b integer,
check ((a IS NULL) != (b IS NULL))
);
Of course that works exclusively with only two column XOR
comparison. With three or more column XOR
comparison in a similar test table you could resort to a similar approach more like this:
create table test
(
id integer primary key,
a integer,
b integer,
c integer,
check ((a IS NOT NULL)::INTEGER +
(b IS NOT NULL)::INTEGER +
(c IS NOT NULL)::INTEGER = 1)
);