sql >> Database >  >> RDS >> PostgreSQL

Relatie met refererende sleutels beperken tot rijen met gerelateerde subtypes

Vereenvoudig bouwen op MATCH SIMPLE gedrag van fk-beperkingen

Als ten minste één kolom met een buitenlandse beperking met meerdere kolommen met standaard MATCH SIMPLE gedrag is NULL , wordt de beperking niet gehandhaafd. U kunt daarop voortbouwen om uw ontwerp grotendeels te vereenvoudigen.

CREATE SCHEMA test;

CREATE TABLE test.status(
   status_id  integer PRIMARY KEY
  ,sub        bool NOT NULL DEFAULT FALSE  -- TRUE .. *can* be sub-status
  ,UNIQUE (sub, status_id)
);

CREATE TABLE test.entity(
   entity_id  integer PRIMARY KEY
  ,status_id  integer REFERENCES test.status  -- can reference all statuses
  ,sub        bool      -- see examples below
  ,additional_col1 text -- should be NULL for main entities
  ,additional_col2 text -- should be NULL for main entities
  ,FOREIGN KEY (sub, status_id) REFERENCES test.status(sub, status_id)
     MATCH SIMPLE ON UPDATE CASCADE  -- optionally enforce sub-status
);

Het is erg goedkoop om enkele extra NULL-kolommen op te slaan (voor hoofdentiteiten):

BTW, per documentatie:

Demo-gegevens:

INSERT INTO test.status VALUES
  (1, TRUE)
, (2, TRUE)
, (3, FALSE);     -- not valid for sub-entities

INSERT INTO test.entity(entity_id, status_id, sub) VALUES
  (11, 1, TRUE)   -- sub-entity (can be main, UPDATES to status.sub cascaded)
, (13, 3, FALSE)  -- entity  (cannot be sub,  UPDATES to status.sub cascaded)
, (14, 2, NULL)   -- entity  (can    be sub,  UPDATES to status.sub NOT cascaded)
, (15, 3, NULL)   -- entity  (cannot be sub,  UPDATES to status.sub NOT cascaded)

SQL Fiddle (inclusief je tests).

Alternatief met enkele FK

Een andere optie zou zijn om alle combinaties van (status_id, sub) . in te voeren in de status tabel (er kunnen er maar 2 zijn per status_id ) en hebben slechts één fk-beperking:

CREATE TABLE test.status(
   status_id  integer
  ,sub        bool DEFAULT FALSE
  ,PRIMARY KEY (status_id, sub)
);

CREATE TABLE test.entity(
   entity_id  integer PRIMARY KEY
  ,status_id  integer NOT NULL  -- cannot be NULL in this case
  ,sub        bool NOT NULL     -- cannot be NULL in this case
  ,additional_col1 text
  ,additional_col2 text
  ,FOREIGN KEY (status_id, sub) REFERENCES test.status
     MATCH SIMPLE ON UPDATE CASCADE  -- optionally enforce sub-status
);

INSERT INTO test.status VALUES
  (1, TRUE)       -- can be sub ...
  (1, FALSE)      -- ... and main
, (2, TRUE)
, (2, FALSE)
, (3, FALSE);     -- only main

enz.

Gerelateerde antwoorden:

Bewaar alle tafels

Als je alle vier de tabellen nodig hebt om de een of andere reden die niet in de vraag staat, overweeg dan deze gedetailleerde oplossing voor een zeer vergelijkbare vraag op dba.SE:

Overerving

... is misschien een andere optie voor wat je beschrijft. Als je kunt leven met enkele belangrijke beperkingen . Gerelateerd antwoord:




  1. MySQL - Meerdere resultatensets

  2. Update zonder waar-clausule

  3. RSA in Android produceert juiste sleutels maar verkeerde decodering

  4. Nulls sorteren als laatste