Najlepsze podejście do modelowania danych do obsługi redundantnych kluczy obcych w bazie danych na temat ankiet, pytań i odpowiedzi

13

Szukam porady na temat najlepszego podejścia do modelowania relacyjnego do przechowywania ankiet, pytań i odpowiedzi.

Szukam, które z dwóch poniższych podejść wygląda najlepiej, lub alternatywne podejście do obu.

Mam przynajmniej te podmioty:

  • pytanie
  • Ankieta
  • osoba

I przynajmniej te relacje:

  • Każda ankieta ma 1 lub więcej pytań.
  • Każde pytanie może być użyte w 0 lub więcej ankietach.
  • Każda osoba może wziąć 0 lub więcej ankiet.

Oto gdzie mam problemy: jak modelować odpowiedzi na pytania ankietowe zadane przez osobę.

Oto dwa podejścia, które rozważałem, z których żadne nie wydaje mi się zbyt dobre. Schematy tutaj są znacznie uproszczone, aby zilustrować problem.

Podejście 1: Podejście 1

Czego nie lubię w tym podejściu:

  • survey_person_question_responseStół ma dwie różne kolumny, które odnoszą się do badań: survey_question_survey_idasurvey_person_survey_id
    • Błędem byłoby mieć różne survey_idodniesienia w jednym wierszu dla tych dwóch kolumn. Ankieta musi pochodzić z tej samej ankiety, co osoba wzięta w ankiecie. Nie widzę dobrego sposobu na wymuszenie tego.
  • Wygląda na to, że to, co tutaj robię, polega na tworzeniu relacji między dwoma związkami. Z jakiegoś powodu wydaje mi się to złe.

Podejście 2:

Staraj się unikać dwóch FK z podejścia 1, które powinny odnosić się do tej samej wartości ... wprowadź opis zdjęcia tutaj

Czego nie lubię w tym podejściu:

  • Nie ma wymuszania, że question_idi survey_idFK pochodzą z prawidłowej survey_questionpary
  • Nie ma wymuszania, że survey_idi person_idFK pochodzą z prawidłowej survey_personpary

Wszelkie porady dotyczące:

  • Czy jedno z tych podejść jest typowe
  • Zalety i wady jednego z tych podejść w stosunku do drugiego
  • Lepszy sposób na całkowite uporządkowanie tych danych

Byłbym bardzo wdzięczny!

deadcode
źródło

Odpowiedzi:

12

Zgodnie z moim rozumieniem twoich specyfikacji, twoje środowisko biznesowe obejmuje relacje trójstronne na poziomie koncepcyjnym . W związku z tym musisz zdefiniować:

  1. typ relacji (lub powiązania ) między typami jednostek Osoba i ankieta ;
  2. rodzaj relacji między ankietą a pytaniem ;
  3. typ relacji, który ustanawia połączenie między dwoma wyżej wymienionymi typami relacji, aw konsekwencji między osobą , ankietą i pytaniem , tj. odpowiedź (krótsza nazwa, która upraszcza interpretację, z mojego punktu widzenia).

Uważam więc, że podążasz właściwą drogą z podejściem 1 , chociaż wymaga ona drobnych (ale ważnych) udoskonaleń, aby uczynić ją bardziej dokładną. Szczegółowo przedstawię takie udoskonalenia i inne istotne uwagi w poniższych sekcjach.

Zasady biznesowe

Rozwińmy nieco obowiązujące reguły biznesowe i przeformułujmy je w następujący sposób:

  • Osoby rejestry zero-jeden-or-wielu ankietach
  • Survey dostaje rejestrację zero-jeden-lub-wiele osób
  • Survey jest zintegrowany przez jeden-do-wielu pytań
  • Pytanie integruje zero-jeden-lub-many Surveys
  • Pytanie otrzymuje zero-jeden-lub-wiele Odpowiedzi
  • Response jest dokładnie-jednej osoby w kontekście dokładnie jeden lat Survey

Schemat IDEF1X dla ekspozytora

Potem stworzyliśmy IDEF1X się schemat, który jest przedstawiony na rysunku 1 , który syntetyzuje reguł biznesowych sformułowanych powyżej:

Ryc. 1 Uproszczone badanie IDEF1X


Definicja Integration for Information Modeling ( IDEF1X ) jest godne polecenia technika modelowania, które powstało jako standardu w grudniu 1993 roku przez Narodowy Instytut Standardów Stanów Zjednoczonych i Technologii ( NIST ). Jest solidnie oparte na pracach teoretycznych autorem przez jedynego założyciela tego modelu relacyjnego , czyli dr EF Codd a także na widoku związków encji opracowanej przez dr PP Chen .


PersonSurvey relacja

Moim zdaniem relacja PersonSurvey jest wymagana, aby zapewnić sposób autoryzacji, aby osoba mogła wziąć udział w ankiecie . W ten sposób, gdy dana osoba zostanie zarejestrowana w konkretnej ankiecie , jest ona upoważniona do udzielania odpowiedzi na pytania, które obejmują odpowiednią ankietę .

SurveyQuestion relacja

Zakładam, że właściwość (lub atrybut) o nazwie suvery_question.question_number na diagramie jest używana do reprezentowania kolejności prezentacji danego wystąpienia pytania w odniesieniu do określonej ankiety . Jak widać, mam taką właściwość oznaczona jako SurveyQuestion.PresentationOrder i myślę, że należy zapobiec, że (i) dwóch lub więcej Question.QuestionNumber wartości akcji (ii) ta sama PresentationOrder wartość w (iii) tego samego SurveyQuestion wystąpienia.

Aby zilustrować tę potrzebę, dołączyłem złożony klucz ALTERNATYWNY (AK) w polu reprezentującym ten typ jednostki, który składa się z kombinacji właściwości ( SurveyNumber, QuestionNumber, PresentationOrder ). Jak dobrze wiadomo, złożoną AK można zadeklarować w logicznym projekcie DDL za pomocą wielokolumnowego ograniczenia UNIQUE (jak zilustrowałem to w SurveyQuestiontabeli, która jest częścią układu DDL ekspozycyjnego objaśnionego w kilku sekcjach poniżej).

Odpowiedzi typu jednostki

Tak, z typem jednostki odpowiedzi przedstawiam relację między dwoma innymi relacjami ; to może wydawać się niewygodne na pierwszy rzut oka, ale nie ma nic złego z tym podejściem, tak długo, jak to (a) reprezentuje cechy kontekście biznesowym zainteresowania dokładnie i (b) jest prawidłowo reprezentowana w układzie logicznym poziomie.

Tak, masz całkowitą rację, błędem byłoby zobrazowanie tej części scenariusza na logicznym poziomie abstrakcji za pomocą dwóch Response.SurveyNumber(lub powiedzmy Response.SurveyId) wartości, do których odnoszą się dwie różne kolumny w tym samym Responserzędzie.

Pochodzi logiczny układ 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)
);

Dwa złożone KLUCZE ZAGRANICZNE w Responsetabeli

Jest to prawdopodobnie najważniejszy punkt do omówienia: odniesienia z danego Responsewiersza do

  1. SurveyQuestion.SurveyNumber, i
  2. SurveyPerson.SurveyNumber

musi mieć pasujące wartości . Jeśli chodzi o mnie, najlepszą opcją do egzekwowania tego warunku w deklaratywny sposób jest użycie dwóch złożonych KLUCZÓW ZAGRANICZNYCH (FK).

Jak pokazano w projekcie DDL, pierwszy FK odnosi się do PersonSurveytabeli KLUCZ PODSTAWOWY (PK), tj. (PersonId, SurveyNumber)I jest zgodny z kolumnami Response.PersonIdi Response.SurveyNumber.

Drugi FK wskazuje na SurveyQuestiontabelę PK, tj. (SurveyNumber, QuestionNumber)I odpowiednio składa się z kolumn Response.SurveyNumberi Response.QuestionNumber.

W ten sposób Response.SurveyNumberkolumna jest dość instrumentalna, ponieważ jest używana jako część odniesienia FK w dwóch różnych ograniczeniach.

Dzięki tej metodzie, jeden gwarantuje zarządzania bazą danych systemu gwarantuje integralności referencyjnej z

  • (a) Responsedo PersonSurvey;
  • (b) Responsedo SurveyQuestion; i
  • (c) każdy z tabel przedstawiających asocjacyjny typu jednostki do tabel stałego niezależnych typów elementów, a mianowicie Person, Surveyi Question.

Dane pochodne, aby uniknąć nieprawidłowości aktualizacji

Na twoim diagramie zauważyłem dwa elementy, które uważam za warte wspomnienia. Te elementy są powiązane z dwiema PersonSurveykolumnami, które można (należy) wyprowadzić .

W tym względzie można uzyskać dane PersonSurvey.IsStartedodniesienia, sprawdzając, czy dane Personwystąpienie dostarczyło jedną lub więcej takich danych Responsesdo Questionszintegrowania za Surveypomocą SurveyQuestiontabeli.

Możesz także uzyskać PersonSurvey.IsCompletedpunkt danych, określając, czy dana Personinstancja dostarczyła a Responsewszystkim, Questionsktóre zawierają wartość „PRAWDA” w IsMandatorykolumnie w określonym SurveyQuestionwierszu.

Poprzez wyprowadzenie tych wartości zapobiegasz niektórym anomaliom aktualizacji, które ostatecznie powstałyby, gdybyś zachował takie wartości w SurveyQuestionkolumnie.

Ważna uwaga

Jak słusznie podkreśla @Dave w swoim komentarzu, jeśli napotkasz przyszłe wymagania wymagające zarządzania różnego rodzaju odpowiedziami, które wymagają zarządzania datami, wartościami liczbowymi, wielokrotnym wyborem i innymi możliwymi aspektami, będziesz musiał rozszerzyć ten układ bazy danych.

MDCCL
źródło
1
Wow, to doskonale odpowiedziało na pytanie w mojej głowie, a następnie nauczyło mnie więcej! Ponieważ komentarze powinien zaproponować ulepszenia: To było nieco mylące, że klucze zakończył zarówno IDa Number, ale poza tym to jest fantastyczne. Dziękuję Ci.
Zach Mierzejewski
@Zach Nie ma za co, cieszę się, że post Ci pomógł. Dzięki za opinie, zdecydowanie potrzebne są pewne udoskonalenia.
MDCCL,
1

To jeden z powodów, dla których nie lubię prefiksować kolumn podczas migracji ich jako kluczy obcych. W pierwszym przypadku narzędzie do modelowania może zmusić Cię do prefiksu jednego z nichsurvey_id kolumn w survey_person_question_responsetabeli. Być może będziesz w stanie to zmienić po nawiązaniu relacji.

W razie potrzeby usuń zbędne pole identyfikatora ankiety podczas budowania modelu fizycznego, w którym nie potrzebujesz zduplikowanej kolumny. Jak już zauważyłeś, oba modele mają problemy, ale uważam, że pierwszy model jest ogólnie lepszy.

BillThor
źródło
Dzięki za wgląd - zawaliłem się do 1 kolumny w modelu fizycznym, który egzekwuje wszystko, co chciałem.
deadcode