Взаимно-рекурсивные внешние ключи



Самый частый юзкейс:



- Есть главная сущность

- Есть дочерние сущности

- Главная сущность ссылается на конкретную дочернюю



Пример: у вопроса может быть несколько ответов, но лишь один корректный:



create table questions (

id bigserial not null primary key,

correct_answer_id bigint not null,

question varchar not null

);



create table answers (

id bigserial not null primary key,

question_id bigint not null,

answer varchar not null

);



alter table questions

add foreign key (correct_answer_id) references answers (id);



alter table answers

add foreign key (question_id) references questions (id);




Как тут могут помочь CTE:



Исходя из модели данных, при создании нового вопроса нам сразу же нужно создать для него правильный ответ. Если это делать последовательно, то мы получим конфликт, поскольку при создании одной сущности вторая должна быть уже создана, и наоборот



Но можно воспользовать тем, что CTE проверяет констрейнты лишь после полного своего выполнения и сделать вставку за один запрос:



with question_id as (select nextval('questions_id_seq')),

answer_id as (

insert

into answers (answer, question_id)

values ('Some answer', (select * from question_id)) returning id)

insert

into questions (id, correct_answer_id, question)

values ((select * from question_id), (select * from answer_id), 'Some question’);




Как вы считаете, стоит ли усложнять модель данных в БД взаимно-рекурсивными ключами, или подобные инварианты должны поддерживаться бизнес-логикой?