2008-12-01 3 views
9

Предположим, у меня есть таблица, представляющая класс супер, студентов. И затем у меня есть N таблиц, которые представляют собой подклассы этого объекта (спортсмены, музыканты и т. Д.). Как я могу выразить ограничение, так что студент должен быть смоделирован в одном (не более, не менее) подклассе?Поддержание целостности подкласса в реляционной базе данных

Разъяснения относительно комментариев:

  • Это поддерживается вручную, а не через пакет ОРМ.
  • Проект относится к синтаксису на SQL Server (но было бы неплохо увидеть общее решение)
  • Возможно, это был не лучший пример. Есть несколько сценариев, которые мы можем рассмотреть в отношении подклассификации, и мне просто пришлось придумать этот пример ученика/спортсмена.

A) В истинно объектно-ориентированном варианте возможно, что суперкласс может существовать сам по себе и не нуждается в моделировании в любых подклассах.

B) В реальной жизни любой объект или учащийся может иметь несколько ролей.

C) В конкретном сценарии, который я пытался проиллюстрировать, требовалось, чтобы каждый объект был реализован только в одном подклассе. Подумайте над суперклассом как абстрактной реализацией или просто общими фактами из других классов или экземпляров объектов.

Спасибо всем за ваш вклад, особенно Билл.

+0

Только для уточнения: вы управляете этим вручную или используете решение ORM, такое как спящий режим? – Uri 2008-12-01 23:38:31

+0

Какую базу вы используете? Если вы используете PostgreSQL, у него есть наследование таблицы. – Elijah 2008-12-01 23:50:02

+0

Мне любопытно, почему не может быть умным как спортсмен, так и новичок? – 2008-12-02 00:18:52

ответ

2

Вот несколько возможностей. Один из них - CHECK в каждой таблице, который student_id не отображается ни в одной из других таблиц подтипов сестры. Это, вероятно, дорого, и каждый раз, когда вам нужен новый подтип, вам нужно изменить ограничение во всех существующих таблицах.

CREATE TABLE athletes (
    student_id INT NOT NULL PRIMARY KEY, 
    FOREIGN KEY (student_id) REFERENCES students(student_id), 
    CHECK (student_id NOT IN (SELECT student_id FROM musicians 
         UNION SELECT student_id FROM slackers 
         UNION ...)) 
); 

редактировать: @JackPDouglas правильно указывает на то, что выше форма проверочного ограничения не поддерживается Microsoft SQL Server. На самом деле, на самом деле, оно действительно для стандарта SQL-99 для ссылки на другую таблицу (см. http://kb.askmonty.org/v/constraint_type-check-constraint).

SQL-99 определяет объект метаданных для ограничений с несколькими таблицами. Это называется УКАЗАНИЕ, однако я не знаю РСУБД, которая реализует утверждения.

Возможно, лучший способ сделать первичный ключ в таблице students составным первичным ключом, второй столбец обозначает подтип. Затем ограничьте этот столбец в каждой дочерней таблице одним значением, соответствующим подтипу, представленному этой таблицей. Редактировать: Не нужно делать PK составным ключом в дочерних таблицах.

CREATE TABLE athletes (
    student_id INT NOT NULL PRIMARY KEY, 
    student_type CHAR(4) NOT NULL CHECK (student_type = 'ATHL'), 
    FOREIGN KEY (student_id, student_type) REFERENCES students(student_id, student_type) 
); 

Конечно student_type может так же легко быть целым, я просто показываю его как полукокс для целей иллюстрации.

Если у вас нет поддержки ограничений CHECK (например, MySQL), вы можете сделать что-то подобное в триггере.

Я прочитал ваше наблюдение о том, чтобы убедиться, что строка существует в некоторая таблица подкласса для каждой строки в таблице суперкласса. Я не думаю, что есть практический способ сделать это с помощью метаданных SQL и ограничений. Единственный вариант, который я могу предложить для удовлетворения этого требования, - использовать Single-Table Inheritance. В противном случае вам нужно полагаться на код приложения для его принудительного применения.

Редактировать: JackPDouglas также предлагает использовать дизайн на основе Class Table Inheritance. См. his example или мои примеры аналогичной техники here или here или here.

0

интересная проблема. Конечно, ограничения FK существуют для субтитров, поэтому для них должен быть студент.

Основная проблема: попробуйте установить флажок в поле ввода. Сначала необходимо добавить ученика, чтобы вы не нарушили ограничение FK в подтаблице, поэтому триггер, который выполняет проверку, не будет работать.

Вы можете написать приложение, которое проверяет время от времени, если вы действительно обеспокоены этим. Я думаю, что самый большой страх, хотя и был бы удалением. Кто-то может удалить запись подтаблицы, но не ученика. У вас могут быть триггеры для проверки того, когда элементы удаляются из подтабликов, поскольку это, вероятно, самая большая проблема.

У меня есть db с таблицей для иерархии подкласса, подобной этому. Я использую Hibernate и его отображение правильно, поэтому он автоматически удаляет все. Если вы сделаете это с помощью «руки», я бы всегда удалял родителя с правильными каскадами hehe :)

0

Спасибо, Билл. Вы заставили меня думать ...

Таблица суперкласса имеет столбец подкласса. Каждая из таблиц подкласса имеет ограничение внешнего ключа, а также то, которое определяет, что идентификатор существует с подмножеством таблицы суперкласса (где code = athlete).

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

Редактировать: Bleh, такая хорошая звучащая идея ... Но мешает тот факт, что подзапросы, ссылающиеся на другие таблицы, не поддерживаются. По крайней мере, не в SQL Server.

0

Это может быть исправлено путем добавления ограничения, которые существуют идентификаторы суперкласса в объединении идентификаторов в таблицах подкласса.

В зависимости от того, какой интеллект вы хотите поместить в свою схему (и сколько MS SQL Server позволяет вам разместить там), вам фактически не нужно было бы объединять таблицы подкласса, поскольку вы знаете, что , если идентификатор существует в любой таблице подкласса, он должен существовать в том же подклассе, что и тот, который указан столбцом подкласса.

3

Каждая запись студента будет иметь столбец подкласса (предположим, что для аргумента это CHAR (1)). {A = спортсмен, M = музыкант ...}

Теперь создайте свои таблицы для спортсменов и музыкантов.Они также должны иметь столбец SubClass, но должно быть проверочное ограничение, жестко кодирующее значение для типа таблицы, которую они представляют. Например, вы должны по умолчанию поставить «A» и ограничение CHECK для «A» для столбца SubClass в таблице Athlete.

Свяжите свои таблицы музыкантов и спортсменов с таблицей учеников, используя внешний ключ COMPOSITE для студенческого идентификатора и подкласса. И вы сделали! Пойдите, наслаждайтесь хорошей чашкой кофе.

CREATE TABLE Student (
    StudentID INT NOT NULL IDENTITY PRIMARY KEY, 
    SubClass CHAR(1) NOT NULL, 
    Name VARCHAR(200) NOT NULL, 
    CONSTRAINT UQ_Student UNIQUE (StudentID, SubClass) 
); 

CREATE TABLE Athlete (
    StudentID INT NOT NULL PRIMARY KEY, 
    SubClass CHAR(1) NOT NULL, 
    Sport VARCHAR(200) NOT NULL, 
    CONSTRAINT CHK_Jock CHECK (SubClass = 'A'), 
    CONSTRAINT FK_Student_Athlete FOREIGN KEY (StudentID, Subclass) REFERENCES Student(StudentID, Subclass) 
); 

CREATE TABLE Musician (
    StudentID INT NOT NULL PRIMARY KEY, 
    SubClass CHAR(1) NOT NULL, 
    Instrument VARCHAR(200) NOT NULL, 
    CONSTRAINT CHK_Band_Nerd CHECK (SubClass = 'M'), 
    CONSTRAINT FK_Student_Musician FOREIGN KEY (StudentID, Subclass) REFERENCES Student(StudentID, Subclass) 
); 
1

Если вы заинтересованы в моделировании данных, в дополнение к объекту моделирования, я предлагаю вам посмотреть «реляционная моделирование генерализации специализации» в Интернете.

Раньше там были какие-то хорошие ресурсы, которые хорошо объясняют этот вид рисунка.

Я надеюсь, что эти ресурсы все еще существуют.

Вот упрощенное представление о том, что я надеюсь, что вы найдете.

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

Одним из способов моделирования данных на концептуальном уровне является модель Entity-Relationship (ER). Существуют хорошо известные модели для моделирования ситуации обобщения специализации. Преобразование этих шаблонов ER в таблицы SQL (логический дизайн) довольно просто, хотя вам нужно сделать некоторые варианты дизайна.

Дело, которое вы дали студенту, имеющему несколько ролей, таких как музыкант, вероятно, не иллюстрирует случай, который вас интересует, если я буду читать вас правильно. Вам кажется, что вас интересует случай, когда подклассы взаимоисключающие. Возможно, легче обсуждать случай, когда автомобиль может быть автомобилем, грузовиком или мотоциклом.

Одна из отличий, с которой вы, вероятно, столкнетесь, заключается в том, что общая таблица для суперкласса действительно не нуждается в столбце типа кода. Тип одного экземпляра суперкласса может быть получен путем наличия или отсутствия внешних ключей в различных таблицах подкласса. Является ли умнее включать или опускать код типа, зависит от того, как вы собираетесь использовать данные.

0

Возможно, я добавлю ограничение на проверку.
Создайте ForeignKeys как Nullable. Добавьте проверку, чтобы убедиться, что они не равны нулю, и убедитесь, что они не установлены. CONSTRAINT [CK_HasOneForiegnKey] CHECK ((FK_First! = NULL ИЛИ FK_Second! = NULL) И НЕ (FK_First! = NULL AND FK_Second! = NULL)).

Я не уверен, но я считаю, что это позволит вам установить только один ключ за раз.