2013-08-20 3 views
2

У меня есть parent и child таблица, где child имеет FK, указывающий на PK родительской таблицы. Когда я удаляю что-то в родительской таблице, я могу также удалить дочерние записи, имея ON DELETE CASCADE.Условная операция CASCADE для ограничения внешнего ключа?

Однако в моей таблице parent я вообще не удаляю записи. Вместо этого я установил столбец state = "passive". Я хочу удалить связанные записи в таблице child.

Есть ли у нас что-то вроде «условного КАСКАДА» в Postgres? Или это решение для ручного удаления записей в таблице child?

ответ

1

Вам нужно будет сделать это в триггере, который будет принимать меры в отношении ОБНОВЛЕНИЯ. Где NEW.state = "passive", удалите дочерние строки.

+0

Ну, да он всегда был вариант, чтобы создать триггер, однако мне было интересно, если есть что-то вроде условного каскада в Postgres или в любой СУБД в этом отношении. Во всяком случае, Большое спасибо за ваш ответ. Я ценю! – Kaunteya

+0

Извините, такого животного в PostgreSQL не существует. –

0

Нет ничего подобного «условный КАСКАД». Ближайшая вещь, которая приходит на ум, будет disable triggers. Но это не полезно в вашем случае.

Предположения:
- state определен NOT NULL.
- parent_idnever изменений. Если это так, вы захотите также каскадировать это UPDATE.

условие, чтобы запустить триггер ON UPDATE должен быть:

 NEW.state = "passive" 
AND OLD.state <> "passive" 

.. так как вы не хотите, чтобы вызвать его снова и снова, только один раз, когда родитель установлен на «пассивный».

CREATE OR REPLACE FUNCTION trg_upbef() 
    RETURNS TRIGGER AS 
$func$ 
BEGIN 

DELETE FROM child 
WHERE parent_id = OLD.parent_id; -- OLD works for UPDATE & DELETE 

RETURN NEW; 
END 
$func$ LANGUAGE plpgsql; 

Вместо checking the condition in the trigger function, you can do that in the trigger directly since Postgres 9.0, тем самым экономя немного накладных расходов:

CREATE TRIGGER upd_cascade_del 
BEFORE UPDATE ON parent 
FOR EACH ROW 
WHEN (NEW.state = "passive" AND 
     OLD.state <> "passive")  -- parenthesis required 
EXECUTE PROCEDURE trg_upbef(); 

Не забудьте добавить триггер для ON DELETE а. Обычно вы не удаляете DELETE, но если вы это делаете, вы хотите либо создать исключение, либо каскадировать операцию.
Функция триггера должна быть RETURN OLD, так как NEW в этом случае не определяется. В противном случае тот же:

CREATE OR REPLACE FUNCTION trg_delbef() 
...  
RETURN OLD; 
... 
$func$ LANGUAGE plpgsql; 


CREATE TRIGGER del_cascade_del 
BEFORE DELETE ON parent 
FOR EACH ROW 
WHEN (OLD.state <> "passive")  -- only if not already passive 
EXECUTE PROCEDURE trg_delbef(); 
Смежные вопросы