1
CREATE TABLE my_table
(
    fk      INTEGER,
    field_1 INTEGER,
    field_2 INTEGER,
    field_3 INTEGER
)

VALID:

    fk    |    field_1    |    field_2    |    field_3              
----------+---------------+---------------+---------------
     1    |      1        |      null     |      null
     1    |      null     |      1        |      null
     1    |      null     |      null     |      1

It's possible to create check constraint which allows only 1 field of 3 can be not null for 1 fk ?

1
  • Yes, but that might not be the best idea. Commented Apr 5, 2012 at 11:03

2 Answers 2

2

The straight forward way come to mind:

CHECK ((field_1 IS NOT NULL AND field_2 IS NULL AND field_3 IS NULL) OR
       (field_2 IS NOT NULL AND field_1 IS NULL AND field_3 IS NULL) OR
       (field_3 IS NOT NULL AND field_1 IS NULL AND field_2 IS NULL))
Sign up to request clarification or add additional context in comments.

Comments

1

It is not quite clear what you'd like to achieve.

If you need only one column being NOT NULL per row, then Nitram's answer will do, you can also try:

CHECK ((sign(coalesce(field_1,0)) +
        sign(coalesce(field_2,0)) + sign(coalesce(field_3,0))) <= 1)

Otherwise, if you need to have only single NOT NULL column per all rows with the given FK, you should look into the CONSTRAINT TRIGGER, something like this:

CREATE OR REPLACE FUNCTION only_one() RETURNS trigger AS $only_one$
DECLARE
    cnt  int4;
BEGIN
    SELECT sign(coalesce(field_1,0)) +
           sign(coalesce(field_2,0)) +
           sign(coalesce(field_3,0)) +
           sign(coalesce(NEW.field_1,0)) +
           sign(coalesce(NEW.field_2,0))+
           sign(coalesce(NEW.field_3,0))
      INTO cnt
      FROM my_table WHERE fk = NEW.fk;

    IF cnt > 1 THEN
        RAISE EXCEPTION 'Sorry, too much NOT NULL values for FK=%', NEW.fk;
    END IF;

    RETURN NEW;
END;
$only_one$ LANGUAGE plpgsql;
CREATE CONSTRAINT TRIGGER my_table_only_one 
 AFTER INSERT OR UPDATE ON my_table
   FOR EACH ROW EXECUTE PROCEDURE only_one();

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.