Проблема в том, что вы ввели значение для SpellSource
, для которого нет соответствующего ClassName
в таблице CLASS
. Столбец может быть частью разных внешних ключей, если это разные составные ключи. Например. FK (a, b)
, FK (b, c)
, где b
принадлежит 2 ФК. Но в остальном один столбец (как правило) должен иметь только один FK.
Кроме того, если у вас есть классы и подклассы, вы бы ссылались здесь только на подкласс и создаете отношение 1 к n между классом и подклассом. То есть подкласс будет иметь внешний ключ для ClassID
SPELL_SOURCE SPELLS
+------------- ---+ +---------------+
| PK FK SpellID | o-----> | PK SpellID |
| PK FK SubclassID | o--+ | SpellName |
+------------------+ | +---------------+
|
| SUBCLASS CLASS
| +-----------------+ +---------------+
+--> | PK SubclassID | +--> | PK ClassID |
| SubclassName | | | ClassName |
| FK ClassID | O--+ +---------------+
+-----------------+
Не используйте имена в качестве PK. Это будет очень трудно изменить имена позже. Вместо этого обращайтесь только к первичному ключу int IDENTITY(1,1)
(автоинкремент), который никогда не изменяется, и сохраняйте имя в отдельном столбце, который вы можете редактировать в любое время. См .: CREATE TABLE (Transact-SQL) IDENTITY (Свойство) .
Вы можете запросить объединенную информацию с помощью
SELECT
SS.SpellID, SS.SubclassID,
S.SpellName,
C.ClassName,
SC.SubclassName, SC.ClassID
FROM
SPELL_SOURCE SS
INNER JOIN SPELLS S
ON SS.SpellID = S.SpellID
INNER JOIN SUBCLASS SC
ON SS.SubclassID = SC.SubclassID
INNER JOIN CLASS C
ON SC.ClassID = C.ClassID
ORDER BY
C.ClassName, SC.SubclassName, S.SpellName
Но учтите, что при таком дизайне одно и то же заклинание может принадлежать разным классам и подклассам. Если заклинание может принадлежать только одному подклассу, то структура должна выглядеть следующим образом.
Class 1 --> n Subclass 1 --> n Spell
Согласно вашим комментариям заклинание может принадлежать классу вместо подкласса (и косвенно также к классу). Тогда я бы предложил следующую структуру
SPELL_SOURCE (separate PK because of nullables, Unique Constraint UC instead)
+------------------+ SPELLS
| PK SpellSourceID | +---------------+
| FK UC SpellID | o---------> | PK SpellID |
| FK UC SubclassID | o------+ | SpellName |
| FK UC ClassID | o--+ | +---------------+
+------------------+ | |
| | SUBCLASS CLASS
| | +-----------------+ +-----> +---------------+
| +--> | PK SubclassID | | +--> | PK ClassID |
| | SubclassName | | | | ClassName |
| | FK ClassID | o--+ | +---------------+
| +-----------------+ |
| |
+----------------------------------+
Где в SPELL_SOURCE
оба ClassID
и SubclassID
НУЖНЫ. Всегда только один из двух будет не нулевым. Вы можете добавить ограничение CHECK (ClassID IS NULL AND SubclassID IS NOT NULL) OR (ClassID IS NOT NULL AND SubclassID IS NULL)
. И используйте ЛЕВЫЕ СОЕДИНЕНИЯ в запросе.
См .: http://www.sqlfiddle.com/#!18/107dd/3/0
Еще один подход состоял бы в том, чтобы сохранить первую структуру, но иметь основную запись или запись подкласса по умолчанию в каждом классе. Например, подкласс, имеющий SubclassName = NULL. Эта запись будет репрезентативной для класса.
Для раскрывающихся списков вы можете выбрать записи, подобные этой
SELECT
S.SubclassID,
CASE WHEN S.SubclassName IS NULL THEN
'CLASS: ' + C.ClassName
ELSE
S.SubclassName + ' (' + C.ClassName + ')'
END AS Name
FROM
CLASS C
INNER JOIN SUBCLASS S
ON C.ClassID = S.ClassID
ORDER BY
C.ClassName,
CASE WHEN S.SubclassName IS NULL THEN 0 ELSE 1 END,
S.SubclassName
См .: http://www.sqlfiddle.com/#!18/d8777/1/0