What is the best way to enforce a 'subset' relationship with integrity constraints

前端 未结 12 1329
一个人的身影
一个人的身影 2020-12-10 18:11

For example, given 3 tables:

  • gastropod
  • snail
  • slug

and assuming we want to enforce that

  1. every row in \'gastropod\
12条回答
  •  南方客
    南方客 (楼主)
    2020-12-10 18:38

    I'd go with

    DROP TABLE GASTROPOD PURGE;
    DROP TABLE SNAIL PURGE;
    
    CREATE TABLE GASTROPOD
      (GASTROPOD_ID NUMBER,
      GASTROPOD_TYPE VARCHAR2(5),
      SNAIL_ID NUMBER,
      SLUG_ID NUMBER,
      CONSTRAINT GASTROPOD_PK PRIMARY KEY (GASTROPOD_ID),
      CONSTRAINT GASTROPOD_TYPE_CK CHECK (GASTROPOD_TYPE IN ('SLUG','SNAIL')),
      CONSTRAINT GASTROPOD_SLUG_CK CHECK 
         (SNAIL_ID IS NOT NULL OR SLUG_ID IS NOT NULL),
      CONSTRAINT GASTROPOD_SNAIL_CK1 CHECK 
         (GASTROPOD_TYPE = 'SNAIL' OR SLUG_ID IS NULL),
      CONSTRAINT GASTROPOD_SLUG_CK1 CHECK 
         (GASTROPOD_TYPE = 'SLUG' OR SNAIL_ID IS NULL),
      CONSTRAINT GASTROPOD_SNAIL_CK2 CHECK (SNAIL_ID = GASTROPOD_ID),
      CONSTRAINT GASTROPOD_SLUG_CK2 CHECK (SLUG_ID = GASTROPOD_ID),
      CONSTRAINT GASTROPOD_SNAIL_UK UNIQUE (SNAIL_ID),
      CONSTRAINT GASTROPOD_SLUG_UK UNIQUE (SLUG_ID)
      );
    

    So you check that a gastropod is a snail or slug and either slug_id or snail_id is set. If it is a snail, then slug_id must be null, and for a slug then snail_id must be null. Make sure slug and snail ids are unique (I've added checks to match them to gastropod_id too).

    CREATE TABLE SNAIL
      (SNAIL_ID NUMBER,
       CONSTRAINT SNAIL_PK PRIMARY KEY (SNAIL_ID),
       CONSTRAINT SNAIL_FK FOREIGN KEY (SNAIL_ID)
         REFERENCES GASTROPOD (SNAIL_ID));
    

    Snails must point to a row in gastropod where snail_id is not null, and it is also the primary key (and therefore unique)

    ALTER TABLE GASTROPOD ADD CONSTRAINT SNAIL_GS_FK FOREIGN KEY (SNAIL_ID)
         REFERENCES SNAIL (SNAIL_ID) DEFERRABLE INITIALLY DEFERRED;
    

    Gastropods with a snail_id set must also have a corresponding row in snail. I've made this direction deferrable, otherwise you'll never get any new data it.

提交回复
热议问题