Найкращий підхід до моделювання даних для обробки зайвих сторонніх ключів у базі даних про опитування, запитання та відповіді


13

Я шукаю поради щодо найкращого підходу реляційного моделювання для зберігання опитувань, запитань та відповідей.

Я шукаю, який із двох підходів нижче виглядає найкращим, або альтернативний підхід до будь-якого.

У мене є принаймні такі суб'єкти:

  • питання
  • опитування
  • особа

І принаймні ці стосунки:

  • Кожне опитування має 1 або більше питань.
  • Кожне питання може використовуватися в 0 або більше опитуваннях.
  • Кожна людина може взяти 0 або більше опитувань.

Ось де я зіткнувся з проблемою: як моделювати відповіді на запитання опитування, зроблені людиною.

Ось два підходи, які я розглянув, жоден з яких не здається мені дуже хорошим. Діаграми тут значно спрощені для ілюстрації проблеми.

Підхід 1: Підхід 1

Що мені не подобається в такому підході:

  • У survey_person_question_responseтаблиці є два різні стовпці, які посилаються на опитування: survey_question_survey_idтаsurvey_person_survey_id
    • Було б помилкою вказати різні survey_idпосилання на один рядок для цих двох стовпців. Питання опитування повинно бути проведене з того самого опитування, що і особа, яка взяла участь у опитуванні_персона. Я не бачу хорошого способу цього виконати.
  • Схоже, те, що я тут роблю, - це створення відносин між двома стосунками. Це мені чомусь не так.

Підхід 2:

Постарайтеся уникати двох ФК від підходу 1, які мають посилатися на одне значення ... введіть тут опис зображення

Що мені не подобається в такому підході:

  • Не існує примусового виконання, щоб ФС question_idі survey_idФК були від дійсної survey_questionпари
  • Не існує примусового виконання, щоб ФС survey_idі person_idФК були від дійсної survey_personпари

Будь-які поради щодо:

  • Чи є один із цих підходів типовим підходом
  • Плюси і мінуси одного з цих підходів над іншим
  • Кращий спосіб упорядкувати ці дані

Будемо дуже вдячні!

Відповіді:


12

Згідно з моїм розумінням ваших специфікацій, ваше ділове середовище передбачає потрійні стосунки на рівні концептуального рівня . У зв'язку з цим вам потрібно визначити:

  1. тип взаємозв'язку (або асоціації ) між сутнісними типами Person та Survey ;
  2. тип відносин між опитуванням і питанням ;
  3. тип відносин, який встановлює зв'язок між двома вищезазначеними типами відносин і, як наслідок, між особою , опитуванням і питанням , тобто відповідь (коротша назва, що спрощує тлумачення, з моєї точки зору).

Отже, я вважаю, що ви підходите до правильного шляху зі своїм Підходом 1 , хоча для його отримання потрібні деякі невеликі (але важливі) уточнення, щоб зробити його більш точним. Я деталізую такі уточнення та інші відповідні міркування в наступних розділах.

Правила бізнесу

Давайте трохи розширимо діючі правила бізнесу та переформулюємо їх наступним чином:

  • Person регістрів в нуль один або-багатьох обстежень
  • Survey отримує реєстрацію нульовий один або-багатьох людей
  • Survey інтегрується один-ко-многим питань
  • Питання інтегрує нульовий один або багатьом Surveys
  • Питання отримує нуль-один або багатьох відповідей
  • Відповідь забезпечується точно-один Людина в контексті точно один рік обстеження

Діаграма IDEF1X експозиторії

Потім я створив IDEF1x на схему , що представлено на малюнку 1 , який синтезує бізнес - правила , сформульовані вище:

Рис.1 Спрощене опитування IDEF1X


Визначення інтеграції для інформаційного моделювання ( IDEF1X ) є вельми рекомендується метод моделюванняякий був створенийякості стандарту в грудні 1993 року Національним інститутом Сполучених Штатів стандартів і технологій ( NIST ). Вона міцно заснована на теоретичну роботі авторства єдиним засновником в реляційної моделі , тобто д - р Ф. Кодда , а також на погляді суті-зв'язку , розроблений д - ром П. Чен .


PersonSurvey відносини

Як я бачу, відносини PersonSurvey зобов’язані забезпечити спосіб авторизації, щоб особа могла брати участь у даному опитуванні . Таким чином, після того, як певна особа була зареєстрована в конкретному опитуванні , вона або вона уповноважена надавати відповіді на запитання, що інтегрують відповідне опитування .

SurveyQuestion відносини

Я припускаю, що властивість (або атрибут) під назвою suvery_question.question_number у вашій діаграмі використовується для представлення Порядку подання даного екземпляра Питання стосовно конкретного опитування . Як ви бачите, я позначив таке властивість, як SurveyQuestion.PresentationOrder , і я вважаю, що вам слід запобігти, щоб (i) два або більше значень Question.QuestionNumber поділили (ii) те саме значення PresentationOrder у (iii) одне й те саме виникнення SurveyQuestion .

Щоб зобразити цю потребу, я включив складений ALTERNATE KEY (AK) у вікно, що представляє цей тип сутності, який складається з поєднання властивостей ( SurveyNumber, QuestionNumber, PresentationOrder ). Як ви добре знаєте, складений АК може бути оголошений в логічному дизайні DDL за допомогою багатоколонного UNIQUE обмеження (як я показав у SurveyQuestionтаблиці, що є частиною макета DDL-експозиції, викладеною в декількох розділах нижче).

Response тип об'єкта

Так, з типом сутності відповіді я зображую зв’язок між двома іншими відносинами ; це може здатися незручним на перший погляд, але в цьому підході немає нічого поганого, доки він (а) точно відображає риси бізнес-контексту, що цікавить, і (б) представлений належним чином у схемі логічного рівня.

Так, ви абсолютно правильні, було б помилкою зобразити ту частину сценарію на логічному рівні абстрагування за допомогою двох Response.SurveyNumber(або, скажімо, Response.SurveyId) значень, посиланих з двох різних стовпців в одному Responseрядку.

Отриманий логічний макет SQL-DDL

-- You should determine which are the most fitting 
-- data types and sizes for all your table columns 
-- depending on your business context characteristics.

-- As one would expect, you are free to make use of 
-- your preferred (or required) naming conventions.

CREATE TABLE Person (
    PersonId        INT      NOT NULL,
    FirstName       CHAR(30) NOT NULL,
    LastName        CHAR(30) NOT NULL,
    GenderCode      CHAR(3)  NOT NULL,
    BirthDate       DATE     NOT NULL,
    CreatedDateTime DATETIME NOT NULL,
    --
    CONSTRAINT Person_PK PRIMARY KEY (PersonId),
    CONSTRAINT Person_AK UNIQUE      (
        FirstName,
        LastName,
        GenderCode,
        BirthDate
    )
);

CREATE TABLE Survey (
    SurveyNumber    INT       NOT NULL,
    Description     CHAR(255) NOT NULL,
    CreatedDateTime DATETIME  NOT NULL,
    --
    CONSTRAINT Survey_PK PRIMARY KEY (SurveyNumber),
    CONSTRAINT Survey_AK UNIQUE      (Description)
);

CREATE TABLE PersonSurvey (
    PersonId           INT      NOT NULL,
    SurveyNumber       INT      NOT NULL,
    RegisteredDateTime DATETIME NOT NULL,
    --
    CONSTRAINT PersonSurvey_PK         PRIMARY KEY (PersonId, SurveyNumber),
    CONSTRAINT PersonSurveyToPerson_FK FOREIGN KEY (PersonId)
        REFERENCES Person (PersonId),
    CONSTRAINT PersonSurveyToSurvey_FK FOREIGN KEY (SurveyNumber)
        REFERENCES Survey (SurveyNumber)
);

CREATE TABLE Question (
    QuestionNumber  INT       NOT NULL,
    Wording         CHAR(255) NOT NULL,
    CreatedDateTime DATETIME  NOT NULL,
    --
    CONSTRAINT Question_PK PRIMARY KEY (QuestionNumber),
    CONSTRAINT Question_AK UNIQUE      (Wording)
);

CREATE TABLE SurveyQuestion (
    SurveyNumber       INT      NOT NULL,
    QuestionNumber     INT      NOT NULL,
    PresentationOrder  TINYINT  NOT NULL,
    IsMandatory        BIT      NOT NULL,
    IntegratedDateTime DATETIME NOT NULL,
    --
    CONSTRAINT SurveyQuestion_PK PRIMARY KEY (SurveyNumber, QuestionNumber),
    CONSTRAINT SurveyQuestion_AK UNIQUE      (
        QuestionNumber,
        SurveyNumber,
        PresentationOrder
    ),
    CONSTRAINT SurveyQuestionToSurvey_FK   FOREIGN KEY (SurveyNumber)
        REFERENCES Survey   (SurveyNumber),
    CONSTRAINT SurveyQuestionToQuestion_FK FOREIGN KEY (QuestionNumber)
        REFERENCES Question (QuestionNumber)
);

CREATE TABLE Response (
    SurveyNumber     INT      NOT NULL,
    QuestionNumber   INT      NOT NULL,
    PersonId         INT      NOT NULL,
    Content          TEXT     NOT NULL,
    ProvidedDateTime DATETIME NOT NULL,
    --
    CONSTRAINT Response_PK                 PRIMARY KEY (SurveyNumber, QuestionNumber, PersonId),
    CONSTRAINT ResponseToPersonSurvey_FK   FOREIGN KEY (PersonId, SurveyNumber)
        REFERENCES PersonSurvey   (PersonId, SurveyNumber),
    CONSTRAINT ResponseToSurveyQuestion_FK FOREIGN KEY (SurveyNumber, QuestionNumber)
        REFERENCES SurveyQuestion (SurveyNumber, QuestionNumber)
);

Два складених зовнішніх ключі в Responseтаблиці

Це, мабуть, найважливіший момент для обговорення: посилання, зроблені із заданого Responseрядка до

  1. SurveyQuestion.SurveyNumber, і
  2. SurveyPerson.SurveyNumber

повинні мати відповідні значення . Наскільки я переживаю, найкращим варіантом застосування цієї умови декларативним способом є використання двох складених ЗОВНІШНІХ КЛЮЧІВ (ФК).

Як показано в дизайні DDL, перший FK робить посилання на PersonSurveyтаблицю PRIMARY KEY (PK), тобто (PersonId, SurveyNumber), і відповідає стовпцям Response.PersonIdі Response.SurveyNumber.

Другий FK вказує на SurveyQuestionтаблицю PK, тобто (SurveyNumber, QuestionNumber), і, відповідно, складається з стовпців Response.SurveyNumberі Response.QuestionNumber.

Таким чином, Response.SurveyNumberстовпець є досить інструментальним, оскільки використовується як частина посилання FK у двох різних обмеженнях.

З допомогою цього методу, один забезпечує управління базами даних системи гарантованої кількість посилань цілісність з

  • (а) Responseдо PersonSurvey;
  • (b) Responseдо SurveyQuestion; і
  • (c) кожна з таблиць, що представляють тип асоціативної сутності до таблиць, що стоять для незалежних типів сутності, а саме Person, Surveyта Question.

Отримані дані, щоб уникнути аномалій оновлення

Я помітив у вашій схемі два елементи, які, на мою думку, варто згадати. Ці елементи пов'язані з двома PersonSurveyколонами , які можуть (повинні) бути похідними .

У зв'язку з цим, ви можете вивести PersonSurvey.IsStartedопорну точку, запитуючи , якщо дане Personявище надало один або більше Responsesв Questionsтому , що інтегрувати точне з Surveyдопомогою SurveyQuestionтаблиці.

І ви також можете отримати PersonSurvey.IsCompletedточку даних, визначивши, чи вказаний Personекземпляр подав a Responseна все те, Questionsщо cointain значення 'TRUE' у IsMandatoryстовпчику в певному SurveyQuestionрядку.

Шляхом виведення цих значень ви запобігаєте деяким аномаліям оновлення, які могли б з часом виникнути, якби ви зберегли такі значення у SurveyQuestionстовпці.

Важливий розгляд

Як справедливо зазначає @Dave у своєму коментарі, якщо ви зіткнетеся з майбутнім вимогою, що вимагає управління різними видами відповідей, які передбачають управління датами, числовими значеннями, множинним вибором та іншими можливими аспектами, вам доведеться розширити цю компоновку бази даних.


1
Ого, це чудово відповіло на запитання в моїй голові, а потім навчило мене більше! Оскільки коментарі повинні запропонувати поліпшення: Це було дещо заплутано, що ключі закінчувались обома IDі Number, але в іншому випадку це фантастично. Дякую.
Zach Mierzejewski

@Zach Ви дуже раді, я радий, що повідомлення допомогло вам. Дякуємо за відгуки, деякі уточнення, безумовно, вимагаються.
MDCCL

1

Це одна з причин, чому я не люблю префіксувати стовпці під час переміщення їх як сторонні ключі. У першому випадку інструмент моделювання може змусити вас встановити один із survey_idстовпців survey_person_question_responseтаблиці. Ви можете скорегувати це після встановлення відносин.

При необхідності видаліть зайве поле ідентифікатора опитування, коли ви будуєте фізичну модель там, де не потрібно дублювати стовпчик. Як ви визначили, обидві ваші моделі мають проблеми, але я вважаю, що перша модель краще в цілому.


Дякую за розуміння - я зробив обвал до 1 стовпця у фізичній моделі, який виконує все, що я хотів.
мертвий код
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.