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

Валидиране на уникалност в база данни, когато валидирането има условие за друга таблица

За съжаление, няма толкова просто и чисто решение, колкото за предишния ви въпрос .

Това трябва да свърши работата:

  • Добавете излишен флаг is_published към Child таблица

    ALTER TABLE child ADD column is_published boolean NOT NULL;
    

    Направете го DEFAULT FALSE или каквото обикновено имате в родителските колони при вмъкване.
    Трябва да е NOT NULL за да избегнете вратичка с NULL стойности и по подразбиране MATCH SIMPLE поведение във външни ключове:
    Ограничение за външен ключ за две колони само когато третата колона НЕ е NULL

  • Добавете (привидно безсмислено, но все пак) уникално ограничение към parent(parent_id, is_published)

    ALTER TABLE parent ADD CONSTRAINT parent_fk_uni
    UNIQUE (parent_id, is_published);
    

    От parent_id е първичен ключ, комбинацията ще бъде уникална и в двата случая. Но това е необходимо за следното fk ограничение.

  • Вместо да препраща към parent(parent_id) с просто ограничение за чужд ключ , създайте външен ключ с няколко колони на (parent_id, is_published) с ON UPDATE CASCADE .
    По този начин състоянието на child.is_published се поддържа и налага от системата автоматично и по-надеждно, отколкото бихте могли да приложите с персонализирани тригери:

    ALTER TABLE child
    ADD CONSTRAINT child_special_fkey FOREIGN KEY (parent_id, is_published)
    REFERENCES parent (parent_id, is_published) ON UPDATE CASCADE;
    
  • След това добавете частичен УНИКАЛЕН индекс както в предишния ви отговор.

    CREATE UNIQUE INDEX child_txt_is_published_idx ON child (text)
    WHERE is_published;
    

Разбира се, когато вмъквате редове в child таблица сте принудени да използвате текущото състояние на parent.is_published сега. Но това е смисълът:да се наложи референтна цялост.

Пълна схема

Или, вместо да адаптирате съществуваща схема, ето пълното оформление:

CREATE TABLE parent(
    parent_id serial PRIMARY KEY
  , is_published bool NOT NULL DEFAULT FALSE
--, more columns ...
  , UNIQUE (parent_id, is_published)   -- required for fk
);

CREATE TABLE child (
    child_id serial PRIMARY KEY
  , parent_id integer NOT NULL
  , is_published bool NOT NULL DEFAULT FALSE
  , txt text
  , FOREIGN KEY (parent_id, is_published)
      REFERENCES parent (parent_id, is_published) ON UPDATE CASCADE
);

CREATE UNIQUE INDEX child_txt_is_published_idx ON child (text)
WHERE is_published;



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Spring JDBC + Postgres SQL + Java 8 - конвертиране от/към LocalDate

  2. Защо лека промяна в думата за търсене забавя толкова много заявката?

  3. Обединяване на таблици в колони от съставен чужд/първичен ключ в заявка

  4. Как да поправя, 'PHP' make, в Mac OS X (10.9.4)?

  5. Как да конвертирате епохата на Unix във времева марка