PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

Ограничете връзката на външния ключ до редове от свързани подтипове

Опростете изграждането на MATCH SIMPLE поведение на fk ограничения

Ако поне една колона от многоколонно чуждо ограничение с MATCH SIMPLE по подразбиране поведението е NULL , ограничението не се прилага. Можете да надграждате върху това, за да опростите значително своя дизайн.

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

Той е много евтин за съхраняване на някои допълнителни NULL колони (за основни обекти):

Между другото, по документация:

Демонстрационни данни:

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 (включително вашите тестове).

Алтернатива с един FK

Друг вариант е да въведете всички комбинации от (status_id, sub) в status таблица (може да има само 2 на status_id ) и имат само едно 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

И т.н.

Свързани отговори:

Запазване на всички таблици

Ако имате нужда от всичките четири таблици по някаква причина, която не е във въпроса, разгледайте това подробно решение на много подобен въпрос на dba.SE:

Наследяване

... може да е друга опция за това, което описвате. Ако можете да живеете с някои основни ограничения . Свързан отговор:




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Извличане на множество нива на xml данни с помощта на xpath в postgres

  2. Символ с кодиране UTF8 няма еквивалент в WIN1252

  3. Postgresql SELECT произволен с уникална стойност

  4. Python 3.7 psycopg2 - Грешка при Xcode грешка:командата „gcc“ е неуспешна със статус на изход 1

  5. Как мога да съпоставя последните две думи в изречение в PostgreSQL?