2017-01-30 17 views
3

У меня есть таблица:PG Checker для родитель-ребенок проверки

CREATE TABLE MENUPOINT (
    id BIGINT NOT NULL, 
    parent BIGINT, 
    name VARCHAR(64), 
    CONSTRAINT "MENUPOINT_pkey" PRIMARY KEY(id), 
    CONSTRAINT fkc75dac36251dd346 FOREIGN KEY (parent) 
    REFERENCES MENUPOINT(id) 
    ON DELETE NO ACTION 
    ON UPDATE NO ACTION 
    NOT DEFERRABLE 
); 

И это содержание:

id  parent name 
------------------------ 
1  null  root 
2  1   child 

Все это, чтобы создать такую ​​структуру:

root 
+- child 

Теперь мне нужно проверите базу данных, чтобы убедиться, что это не может быть выполнено:

UPDATE MENUPOINT SET parent = 2 WHERE id = 1; 

Потому что:

  1. я не смог бы выяснить, кто является корнем.
  2. Дисплей дерева будет бесконечным, как это:


root 
    +- child 
     +- root 
      +- child 
       +- root .... 

Что у меня есть:

CONSTRAINT "NOT_SELF_REFERENCE" CHECK (id <> parent) 

Но он не проверяет все дерево.

Что нужно изменить для дерева без петлирования?

+0

Отменить обновление этой таблицы из ролей. Это нужно делать исключительно с использованием определенной функции. –

+0

триггер для проверки 'NEW.parent not in (выберите id из menupoint, где parent = NEW.id)'? .. –

+0

@VaoTsun, который проверяет только петли из 2-х элементов. С рекурсивными CTE могут быть обнаружены любые петли. - Но простые триггерные проверки могут работать в условиях гонки при высоком параллелизме (f.ex. 2 одновременных обновления могут создавать цикл, а сами они не будут). Я не уверен, как бы работал «КОНСТРУКТИВНЫЙ ТРИГГЕР» (не нашел ничего, связанного с условиями гонки в них в документах). – pozs

ответ

2

Это слишком длинный комментарий.

Если вы храните иерархические данные, этот пост является отличным местом для start. Вы можете также Google «иерархическое дерево Карвина», поскольку Билл Карвин проводит тщательные исследования по этому вопросу.

Для чего вы хотите, сразу приходят в голову три вещи. Первый - написать функцию для проверки циклов и использовать ее для триггеров insert и update. Это не мой любимый выбор.

Другим вариантом является использование закрывающего стола. В нем перечислены все ссылки между двумя узлами в дереве. Затем может быть использовано модифицированное ограничение check (в основном новое соединение разрешено, если все новые пути действительны, и это можно проверить довольно легко).

Возможно, самым простым (с точки зрения использования) является полный путь. Если каждый узел содержит полный путь от корня, то при вставке вы можете легко проверить существующие полные пути для потенциальных циклов.