For example, given 3 tables:
and assuming we want to enforce that
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.