Я думаю, что вам нужно SQL стандартных утверждения, которые (к сожалению) в основном невыполненные фактическим СУБД.
всех ответов соглашается, что есть три первичные таблицы, называемые TableA, TableB и TableC, каждый из которых содержит свой собственный идентификатор колонки:
TableA (A_ID PRIMARY KEY, ...)
TableB (B_ID PRIMARY KEY, ...)
TableC (C_ID PRIMARY KEY, ...)
это не ясно из описания проблемы, является ли одно значение B может иметь несколько родительских записей A. Понятно, что один C может иметь несколько родительских записей B. Если B привязан к одному A, конструкция TableB может быть пересмотрен:
TableB (B_ID, ..., A_ID REFERENCES TableA)
Если B может быть связан с несколькими разными А-х, то соединение лучше всего представлены соединительной таблице:
Из описания также не ясно, должно ли C, связанное с B, быть одинаковым для каждого A, с которым связано B, или могут ли различные A ссылаться на один B и набор связанных с C с B для A1 может отличаться от набора C, связанного с B для A2. (Конечно, если один B может быть связан только с одним A, этот вопрос является спорным.)
Для целей этого ответа я собираюсь предположить, что любой B связан с одним A, поэтому структура TableB включает A_ID в качестве внешнего ключа. Так как один C может быть связан с несколькими Б, соответствующая структура нового присоединения таблицы:
B_and_C (B_ID REFERENCES TableB,
C_ID REFERENCES TableC,
PRIMARY KEY (B_ID, C_ID)
)
Упрощая (опуская правила о deferrability и непосредственности) утверждение выглядит следующим образом:
CREATE ASSERTION assertion_name CHECK (<search_condition>)
Так , как только мы получим набор проектных решений, мы можем написать утверждение для проверки данных.Учитывая таблицу TableA, TableB (с внешним ключом A_ID), TableC и B_and_C требованием является то, что число вхождений данного C_ID через полный А 1.
CREATE ASSERTION only_one_instance_of_c_per_a CHECK
(
NOT EXISTS (
SELECT A_ID, COUNT(C_ID)
FROM TableB JOIN B_and_C USING (C_ID)
GROUP BY A_ID
HAVING COUNT(C_ID) > 1
)
)
[Измененная: Я думаю, что это является более точным:
CREATE ASSERTION only_one_instance_of_c_per_a CHECK
(
NOT EXISTS (
SELECT A_ID, C_ID, COUNT(*)
FROM TableB JOIN B_and_C USING (C_ID)
GROUP BY A_ID, C_ID
HAVING COUNT(*) > 1
)
)
]
набор условий соединения изменяется с другими правилами для того, как таблицы связаны, но общая структура ограничение остается неизменным - не должно существовать более одного г для определенного C_ID для конкретного A_ID.
В комментариях ниже, meandmycode примечание:
я получаю чувство, что есть ошибка в моей конструкции. Моя реальная логика заключается в том, что у «В» всегда есть хотя бы один ребенок «С». Это не имеет смысла, учитывая, что «B» должен существовать до того, как его ребенок может быть прикреплен. База данных в настоящее время позволяет привязывать «B» к «A», не имея хотя бы одного «C». Ребенок, я как таковой пересматриваю «B», так что у него есть поле, которое ссылается на его основной ребенок «C», а также наличие дочерней коллекции дополнительных «C», но теперь у меня есть коллекция, которая также может включать в себя первичный «C», указанный «B», что было бы неправильно.
Есть ли шаблон db, который выводит правило «одного или нескольких детей», против нуля или более?
У меня возникли проблемы с вашей моделью. Трудно создать B, если уже существует C, который ссылается на вновь созданный B, особенно если C должен относиться только к существующим B. На ум приходит фраза «курица и яйцо». Итак, обычно, вы разрешаете B иметь нулевой или более C в таком контексте.
Вы все еще не указали, есть ли у TableB внешний ключ A_ID или у вас есть таблица ссылок, такая как A_and_B. Если у него есть внешний ключ, то, предположительно, вы не можете создать B до тех пор, пока не создадите A, к которому он относится.
Я не думаю, что один C ID в таблице B является хорошей идеей - это делает для асимметричной обработки (сложнее SQL). Это также означает, что если вам нужно удалить один C, вам необходимо обновить все, чтобы одна из других ссылок на C была удалена из таблицы, в которой она сейчас находится, а затем обновляет значение в записи B. Это грязно, чтобы быть вежливым об этом.
Думаю, вам нужно изменить свой вопрос, чтобы определить фактическую структуру таблицы, на которую вы смотрите, - по линиям, показанным в разных ответах; вы можете использовать тройные точки для представления других, но неуместных столбцов. Утверждение, которое я предложил, вероятно, должно быть реализовано как какой-то триггер, который попадает в специфичные для СУБД записи.
Из измененного описания трусах (А), представления (B) и членов (С), то ясно, что одно представление относится к только один краткий, так что материалы могут иметь простой внешний ключ, который идентифицирует краткое изложение, для которого это представление. Член может сотрудничать только в одном представлении для конкретного краткого сообщения. Будет таблица «submit_collaborators» с столбцами для идентификации представления и участника, комбинация является первичным ключом, а каждый столбец является внешним ключом.
Briefs(Brief_ID, ...)
Submissions(Submission_ID, Brief_ID REFERENCES Briefs, ...)
Members(Member_ID, ...)
Submission_Collaborators(Submission_ID REFERENCES Submissions,
Member_ID REFERENCES Members,
PRIMARY KEY (Submission_ID, Member_ID)
)
Следовательно, требование состоит в том, что следующий запрос не должен возвращать никаких строк:
SELECT s.brief_id, c.member_id, COUNT(*)
FROM submissions AS s JOIN submission_collaborators AS c
ON s.submission_id = c.submission_id
GROUP BY s.brief_id, c.member_id
HAVING COUNT(*) > 1
Это тот же запрос, который я встроен в CREATE утверждение (второй вариант). Вы также можете выделить дополнительную информацию (краткое название, название заявки, имя участника, различные даты и т. Д.), Но суть проблемы заключается в том, что указанный запрос не должен возвращать данные.
+1 для того, чтобы СУБД принудительно применяла ограничение независимо от того, что делают приложения (приложения). –
Я с Джонатаном, слишком много людей считают, что приложение действительно выполняет эту работу и в результате получают плохие данные. – HLGEM
Как видно из моего ответа, ваш сценарий довольно запутан, и если вы можете его изменить, вам следует. Число систем, поддерживающих CREATE ASSERTION, очень ограничено. Утверждение, требуемое для проверки ограничений, является сложным для использования в триггере. –