В моей базе данных есть 3 соответствующие таблицы.
CREATE TABLE dbo.Group
(
ID int NOT NULL,
Name varchar(50) NOT NULL
)
CREATE TABLE dbo.User
(
ID int NOT NULL,
Name varchar(50) NOT NULL
)
CREATE TABLE dbo.Ticket
(
ID int NOT NULL,
Owner int NOT NULL,
Subject varchar(50) NULL
)
Пользователи принадлежат к нескольким группам. Это делается через отношения "многие ко многим", но в данном случае это не имеет значения. Билет может принадлежать группе или пользователю через поле dbo.Ticket.Owner.
Каким будет НАИБОЛЕЕ ПРАВИЛЬНЫЙ способ описания отношений между заявкой и, возможно, пользователем или группой?
Я думаю, что мне следует добавить в таблицу билетов флаг, который говорит, какой тип владеет им.
sql-server
relational-database
Darthg8r
источник
источник
Ответы:
У вас есть несколько вариантов, все они различаются по «правильности» и простоте использования. Как всегда, правильный дизайн зависит от ваших потребностей.
Вы можете просто создать два столбца в Ticket, OwnedByUserId и OwnedByGroupId, и иметь внешние ключи, допускающие значение NULL, для каждой таблицы.
Вы можете создать справочные таблицы M: M, позволяющие устанавливать отношения как билет: пользователь, так и билет: группа. Возможно, в будущем вы захотите разрешить владение одним билетом нескольким пользователям или группам? Такая конструкция не обеспечивает , что билет должен принадлежать только одной организации.
Вы можете создать группу по умолчанию для каждого пользователя и иметь билеты, которые просто принадлежат либо настоящей Группе, либо Группе по умолчанию пользователя.
Или (на мой выбор) смоделировать сущность, которая действует как база как для пользователей, так и для групп, и имеет билеты, принадлежащие этой сущности.
Вот примерный пример использования вашей опубликованной схемы:
источник
SELECT t.Subject AS ticketSubject, CASE WHEN u.Name IS NOT NULL THEN u.Name ELSE g.Name END AS ticketOwnerName FROM Ticket t INNER JOIN Party p ON t.Owner=p.PartyId LEFT OUTER JOIN User u ON u.ID=p.PartyId LEFT OUTER JOIN Group g on g.ID=p.PartyID;
В результате у вас будут все темы и имена владельцев билетов.Первый вариант в списке @Nathan Skerl - это то, что было реализовано в проекте, с которым я когда-то работал, где аналогичные отношения были установлены между тремя таблицами. (Один из них ссылался на двух других, по одному.)
Таким образом, в ссылочной таблице было два столбца внешнего ключа, а также было ограничение, гарантирующее, что только одна таблица (не обе и ни одна) была указана одной строкой.
Вот как это может выглядеть применительно к вашим таблицам:
Как видите,
Ticket
таблица имеет два столбцаOwnerGroup
иOwnerUser
, оба из которых являются внешними ключами, допускающими значение NULL. (Соответствующие столбцы в двух других таблицах соответственно становятся первичными ключами.) КонтрольноеCK_Ticket_GroupUser
ограничение гарантирует, что только один из двух столбцов внешнего ключа содержит ссылку (другой имеет значение NULL, поэтому оба должны допускать значение NULL).(Первичный ключ
Ticket.ID
не требуется для этой конкретной реализации, но, безусловно, не повредит его наличие в такой таблице.)источник
RefID
,RefType
гдеRefType
- фиксированный идентификатор целевой таблицы. Если вам нужна целостность, вы можете выполнять проверки на уровне триггера или приложения. В этом случае возможен общий поиск. SQL должен позволять такое определение FK, что облегчает нашу жизнь.Еще один вариант состоит в том, чтобы иметь в
Ticket
одном столбце, определяющем тип объекта-владельца (User
илиGroup
), второй столбец со ссылкойUser
илиGroup
идентификатором и НЕ использовать внешние ключи, а вместо этого полагаться на триггер для обеспечения ссылочной целостности.Я вижу здесь два преимущества перед превосходной моделью Натана (см. Выше):
источник
Другой подход - создать ассоциативную таблицу, содержащую столбцы для каждого потенциального типа ресурса. В вашем примере каждый из двух существующих типов владельцев имеет свою собственную таблицу (что означает, что вам есть на что ссылаться). Если так будет всегда, у вас может получиться что-то вроде этого:
С помощью этого решения вы продолжите добавлять новые столбцы по мере добавления новых сущностей в базу данных, а также удалите и воссоздайте шаблон ограничения внешнего ключа, показанный @Nathan Skerl. Это решение очень похоже на @Nathan Skerl, но выглядит иначе (в зависимости от предпочтений).
Если у вас не будет новой таблицы для каждого нового типа владельца, то, возможно, было бы хорошо включить owner_type вместо столбца внешнего ключа для каждого потенциального владельца:
С помощью описанного выше метода вы можете добавить столько типов владельцев, сколько захотите. Owner_ID не будет иметь ограничения внешнего ключа, но будет использоваться как ссылка на другие таблицы. Обратной стороной является то, что вам придется взглянуть на таблицу, чтобы увидеть, какие типы владельцев есть, поскольку это не сразу очевидно на основе схемы. Я бы предложил это только в том случае, если вы заранее не знаете типы владельцев, и они не будут связываться с другими таблицами. Если вы заранее знаете типы владельцев, я бы выбрал такое решение, как @Nathan Skerl.
Извините, если я ошибся в SQL, я просто собрал это вместе.
источник
Я думаю, что это был бы наиболее общий способ представить то, что вы хотите, вместо использования флага.
источник