Ссылка на данные из нескольких таблиц - PullRequest
0 голосов
/ 27 ноября 2018

У меня есть три простых объекта:

Курс подобен Книге, продаваемому продукту.Объект «Курс» представляет курс и имеет различные свойства, такие как «Продолжительность», «Плата», «Автор», «Тип» и т. Д.

Course 
{
    int Id;
    string Title;
}

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

Topic
{
    int Id;
    string Title;
}

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

Quiz
{
    int Id;
    string Title;
}

Теперь, когда у меня есть отдельные темы и тесты, я хочу иметь таблицу, которая будет собирать темы и тесты в книгу.Рассматривайте эту таблицу как оглавление в книге.Ниже приводится схема того, как я ожидаю, что это будет выглядеть:

CourseContents
{
     int CourseId; // Foreign-Key to Courses.Id
     int Page;     // Foreign-Key to either Topic.Id or Quiz.Id
     int SNo;      // Sequence of this page (topic/quiz) in the course, much like page number in a book.
     int Type      // Type of the page i.e, Quiz or Topic. 
}

Есть ли способ достичь этого в СУРБД?

Попытка решения

Один из подходов, на которые я смотрю, - это создание таблицы для создания уникального идентификатора для данного элемента курса.Затем используйте его в таблицах сопоставления Courses-Topics и Courses-Quizzes.Пожалуйста, обратитесь ниже:

CourseContents
{
    int Id;        // CourseContentId Primary-Key for this table
    int CourseId;  // Foreign key to Course.Id
    int SNo;       // Serial number of an item in this course;
}

CourseTopics
{
    int TopicId;             // Foreign-Key to Topics.Id
    int CourseContentsId;    // Foreign-Key to CourseContents.Id
}

CourseQuizzes
{
    int QuizId;               // Foreign-Key to Quizzes.Id
    int CourseContentsId;     // Serial number of the quiz in the course
}

Проблема: CourseContentId представляет определенную позицию (темы / теста) в конкретном курсе.Два элемента не могут занимать одну и ту же позицию в последовательности курса, поэтому один CourseContentId должен быть связан только с одним элементом в CourseTopics или CourseQuizzes.Как мы можем наложить уникальное ограничение на CourseContentsId для двух таблиц?

Дальнейшее добавление

Вышеупомянутая проблема может быть решена путем добавления столбца ContentType в CourseContents, CourseTopics и CourseQuizzes.колонка.Затем, применяя Проверьте ограничение к таблицам, убедитесь, что:

  • CourseContents имеет уникальную комбинацию CourseContentId и ContentType.
  • CourseTopics & CourseQuizzes должны иметь одинаковое содержимоеВведите через.
  • Добавление внешнего ключа, ссылающегося на CourseContents (CourseContentId, ContentType) в таблицах CourseTopics и CourseQuizzes.

Это гарантирует, что CourseContentId не появится в обеих таблицах.

Ответы [ 2 ]

0 голосов
/ 06 декабря 2018
CREATE TABLE CourseContents (
  CourseContentsId INTEGER NOT NULL PRIMARY KEY,
  CourseContentType CHAR(1) CHECK (CourseContentType IN ('T', 'Q')),
  CourseId INTEGER REFERENCES Courses(Id),
  SNo INTEGER NOT NULL,
  CONSTRAINT UniqueCourseContent UNIQUE (CourseId, SNo),
  CONSTRAINT UniqueCourseContentMapping UNIQUE (CourseContentsId, CourseContentType),
);

Таблица содержания курса генерирует уникальный идентификатор (CourseContentsId) для каждой комбинации CourseId и SNo, на который затем можно ссылаться в таблице «Темы и тесты».Поскольку существуют две разные таблицы (темы и тесты), мы вводим еще один столбец, в котором указывается тип контента (тема / тест), с которым он связан.Используя составное ограничение UNIQUE для CourseContentsId & CourseContentType, мы гарантируем, что каждая запись может быть связана только с одним типом контента.

CREATE TABLE CourseTopics (
  CourseContentsId INTEGER NOT NULL,
  CourseContentType CHAR(1) DEFAULT 'T' CHECK (CourseContentType = 'T'),
  TopicId INTEGER REFERENCES Topics(Id),
  PRIMARY KEY (CourseContentsId, CourseContentType),
  FOREIGN KEY (CourseContentsId, CourseContentType) REFERENCES CourseContents (CourseContentsId, CourseContentType)
);

Таблица тем курса - это таблица отображения между темами и курсами (у нас есть много-много отношения между таблицами курсов и тем).Внешний и первичный ключ к таблице CourseContents гарантирует, что у нас будет одна запись для каждого CourseContent (другими словами, Course & SNo).Таблица ограничивает CourseContentType только тем, чтобы принимать 'T', что означает, что данный CourseContentId должен иметь тип содержимого Темы, чтобы быть связанным с Темой.

CREATE TABLE CourseQuizzes (
  CourseContentsId INTEGER NOT NULL,
  CourseContentType CHAR(1) DEFAULT 'Q' CHECK (CourseContentType = 'Q'),
  QuizId INTEGER REFERENCES Quizzes(Id),
  PRIMARY KEY (CourseContentsId, CourseContentType),
  FOREIGN KEY (CourseContentsId, CourseContentType) REFERENCES CourseContents (CourseContentsId, CourseContentType)
);

По аналогии с таблицей Тем мы теперь создаем таблицу CourseQuizzes.Единственное отличие состоит в том, что у нас есть CourseContentType 'Q'.

Наконец, чтобы упростить запросы, мы можем создать представление, объединяющее эти таблицы.Например, в представлении ниже будут перечислены: CourseId, SNo, ContentType, TopicId, QuizId.В контексте книги, с помощью этого представления вы можете получить то, что находится на определенном номере страницы (SNo) данной книги (курса), с типом содержимого на странице (тема или викторина) и идентификатором содержимого.

CREATE VIEW CourseContents_All AS 
SELECT CourseContents.CourseId, CourseContents.SNo, CourseContents.CourseContentType , CourseTopics.Id, CourseQuizzes.Id
FROM CourseContents
LEFT JOIN CourseTopics ON (CourseContents.CourseContentsId = CourseTopics.CourseContentsId)
LEFT JOIN CourseQuizzes ON (CourseContents.CourseContentsId = CourseQuizzes.CourseContentsId);

Преимущества, которые я чувствую при таком подходе:

  1. Эта структура следует за наследованием, что означает, что мы можем поддерживать больше типов контента, просто добавив другую таблицу и изменив CourseContentType Проверить ограничение вТаблица CourseContents.
  2. Для заданного идентификатора курса и номера SNo.я также знаю тип контента.Это, безусловно, поможет в коде приложения.

Примечание. Проверочное ограничение не работает в MySQL.Для этого нужно использовать триггеры.

0 голосов
/ 29 ноября 2018

CourseContentId представляет определенную позицию (темы / теста) в конкретном курсе.

CourseTopics
{
    int TopicId;             // Foreign-Key to Topics.Id

    int CourseContentsId;  -- first of 3-part FK
    int Page;              -- added
    int SNo;               -- added
    PRIMARY KEY(TopicId, CourseContentsId, Page, SNo), -- for JOINing one way
    INDEX      (CourseContentsId, Page, SNo, TopicId)  -- for JOINing the otehr way
}

Между тем, ...

I угадайте , что ваша главная проблема заключена в одной строке:

int Page;// Foreign-Key для Topic.Id или Quiz.Id

Это нецелесообразно.Решение состоит в том, чтобы иметь одну таблицу для Topic и Page и отличаться от нее.

...