sql >> Databáze >  >> RDS >> PostgreSQL

Omezte vztah cizího klíče na řádky souvisejících podtypů

Zjednodušte vytváření na MATCH SIMPLE chování fk omezení

Pokud je alespoň jeden sloupec vícesloupcového cizího omezení s výchozí hodnotou MATCH SIMPLE chování je NULL , omezení není vynuceno. Na tom můžete stavět a značně zjednodušit svůj design.

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
);

Je to velmi levné pro uložení některých dalších sloupců NULL (pro hlavní entity):

BTW, podle dokumentace:

Demo-data:

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 (včetně vašich testů).

Alternativa s jedním FK

Další možností by bylo zadat všechny kombinace (status_id, sub) do status tabulka (mohou být pouze 2 na status_id ) a mají pouze jediné omezení fk:

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

atd.

Související odpovědi:

Ponechat všechny tabulky

Pokud potřebujete všechny čtyři tabulky z nějakého důvodu, který není v otázce, zvažte toto podrobné řešení velmi podobné otázky na dba.SE:

Dědičnost

... může být další možností toho, co popisujete. Pokud můžete žít s některými významnými omezeními . Související odpověď:




  1. Co znamená %% v PL/pgSQL?

  2. Kde je soubor MySQL 5.7 my.cnf?

  3. Získání maximální hodnoty z řádků a připojení k jiné tabulce

  4. Použití JShell v Javě 9 v NetBeans 9.0, část 2