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


11

У мене є таблиця відповідей та таблиця запитань .

Таблиця Відповіді має значення, але в залежності від питання, це значення може бути bit, nvarcharабо number( до сих пор). Питання має уявлення про те , що його передбачуване тип значення відповіді повинен бути.

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

Для трохи більше контексту питання та потенційні відповіді (як правило, тип даних, дозволений для введення типу текстового поля), надаються деякими користувачами під час опитування. Потім відповіді надають інші вказані користувачі.

Я розглянув кілька варіантів:

A. XML або рядок, який розбирається по-різному залежно від призначеного типу (про що відстежується у запитанні)

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

C. Три окремі стовпці таблиці відповідей, які можна отримати залежно від призначеного типу.

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

Відповіді:


2

Це дійсно залежить від того, як ваш фасад отримує доступ до даних.

Якщо ви використовуєте O / R-mapper, зосередьтеся на об'єктно-орієнтованому дизайні класів, а не на дизайні бази даних. Потім база даних просто відображає дизайн класу. Точний db-дизайн залежить від O / R-картографа та моделі відображення спадщини, яку ви використовуєте.

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

Крім того, ви можете використовувати один стовпець на тип значення. У нас сьогодні є терабайтні накопичувачі!

Стовпець XML можливий, але, ймовірно, додає більше складності в порівнянні з простим текстовим стовпцем і робить майже те саме, а саме серіалізацію / дезаріалізацію.

Відокремлені з’єднані таблиці - це правильний нормований спосіб робити речі; однак вони також додають певної складності.

Не ускладнювати.

Дивіться також мою відповідь на дизайн бази даних анкети - який спосіб краще? .


4

На основі сказаного вами я використовував би таку загальну схему:

CREATE TABLE [dbo].[PollQuestion]
(
    [PollQuestionId] INT NOT NULL PRIMARY KEY IDENTITY,
    [QuestionText] NVARCHAR(150) NOT NULL, -- Some reasonable character limit
    [Created] DATETIME2(2) NOT NULL DEFAULT SYSUTCDATETIME(),
    [Archived] DATETIME2(2) NULL,  -- Remove this if you don't need to hide questions
)
CREATE TABLE [dbo].[PollOption]
(
    [PollOptionId] INT NOT NULL PRIMARY KEY IDENTITY,
    [PollQuestionId] INT NOT NULL,  -- Link to the question here because options aren't shared across questions
    [OptionText] NVARCHAR(50) NOT NULL, -- Some reasonable character limit
    [Created] DATETIME2(2) NOT NULL DEFAULT SYSUTCDATETIME(),
    [Archived] DATETIME2(2) NULL  -- Remove this if you don't need to hide options

    CONSTRAINT [FK_PollOption_PollQuestionId_to_PollQuestion_PollQuestionId] FOREIGN KEY ([PollQuestionId]) REFERENCES [dbo].[PollQuestion]([PollQuestionId])
)
CREATE TABLE [dbo].[PollResponse]
(
    [PollResponseId] INT NOT NULL PRIMARY KEY IDENTITY,
    [PollOptionId] INT NOT NULL,
    [UserId] INT NOT NULL,
    [Created] DATETIME2(2) NOT NULL DEFAULT SYSUTCDATETIME(),
    [Archived] DATETIME2(2) NULL,  -- Remove this if you don't need to hide answers

    CONSTRAINT [FK_PollResponse_PollOptionId_to_PollOption_PollOptionId] FOREIGN KEY ([PollOptionId]) REFERENCES [dbo].[PollOption]([PollOptionId]),
    CONSTRAINT [FK_PollResponse_UserId_to_User_UserId] FOREIGN KEY ([UserId]) REFERENCES [dbo].[User]([UserId])
)

Вас не цікавить, чи є відповідь цифрою, датою, словом і т. Д., Оскільки дані - це відповідь на питання, а не те, з чим вам потрібно працювати безпосередньо. Крім того, дані мають значення лише в контексті питання. Оскільки такий nvarchar є найбільш універсальним читаним людиною механізмом зберігання даних.

Питання та потенційні відповіді будуть зібрані від першого користувача та вставлені в таблиці PollQuestion та PollOption. Другий користувач, який відповідає на питання, вибере зі списку відповідей (true / false = список із 2). Ви також можете розгорнути таблицю PollQuestion, щоб включити ідентифікатор користувача творця, якщо це доречно, щоб відстежувати створені ними питання.

У вашому інтерфейсі відповідь, яку вибирає користувач, може бути прив’язана до значення PollOptionId. Разом з PollQuestionId ви можете швидко переконатися, що відповідь справедлива для запитання. Їх відповідь, якщо дійсна, буде занесена в таблицю PollResponse.

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

CREATE TABLE [dbo].[PollResponse]
(
    [PollResponseId] INT NOT NULL PRIMARY KEY IDENTITY,
    [PollOptionId] INT NULL,
    [PollQuestionId] INT NOT NULL,
    [UserId] INT NOT NULL,
    [AlternateResponse] NVARCHAR(50) NULL, -- Some reasonable character limit
    [Created] DATETIME2(2) NOT NULL DEFAULT SYSUTCDATETIME(),
    [Archived] DATETIME2(2) NULL,  -- Remove this if you don't need to hide answers

    CONSTRAINT [FK_PollResponse_PollOptionId_to_PollOption_PollOptionId] FOREIGN KEY ([PollOptionId]) REFERENCES [dbo].[PollOption]([PollOptionId]),
    CONSTRAINT [FK_PollResponse_UserId_to_User_UserId] FOREIGN KEY ([UserId]) REFERENCES [dbo].[User]([UserId])
)

Я б, мабуть, також додав обмеження для перевірки, щоб переконатися, що надається варіант або альтернативна відповідь, але не обидва (варіант і альтернативна відповідь), залежно від ваших потреб.

Редагувати: спілкування типу даних для AlternateResponse.

У ідеальному світі ми могли б використовувати концепцію генерики для обробки різних типів даних для AlternateReponse. На жаль, ми не живемо в ідеальному світі. Найкращий компроміс, який я можу придумати, - це вказати, який тип даних AlternateResponse має бути в таблиці PollQuestion, і зберегти AlternateReponse в базі даних як nvarchar. Нижче наведена оновлена ​​схема питань та нова таблиця типів даних:

CREATE TABLE [dbo].[PollQuestion]
(
    [PollQuestionId] INT NOT NULL PRIMARY KEY IDENTITY,
    [QuestionText] NVARCHAR(150) NOT NULL, -- Some reasonable character limit
    [QuestionDataTypeId] INT NOT NULL,
    [Created] DATETIME2(2) NOT NULL DEFAULT SYSUTCDATETIME(),
    [Archived] DATETIME2(2) NULL,  -- Remove this if you don't need to hide questions
    -- Insert FK here for QuestionDataTypeId
)
CREATE TABLE [dbo].[QuestionDataType]
(
    [QuestionDataTypeId] INT NOT NULL PRIMARY KEY IDENTITY,
    [Description] NVARCHAR(50) NOT NULL, -- Some reasonable character limit
)

Ви можете перелічити всі доступні типи даних для творців питань, вибравши цю таблицю QuestionDataType. Ваш інтерфейс може посилатися на QuestionDataTypeId, щоб вибрати правильний формат для альтернативного поля відповіді. Ви не обмежені типами даних TSQL, тому "Номер телефону" може бути типом даних, і ви отримаєте відповідне форматування / маскування в інтерфейсі користувача. Також, якщо потрібно, ви можете передати свої дані відповідним типам за допомогою простого твердження справи, щоб здійснити будь-яку обробку (вибір, перевірку тощо) на альтернативні відповіді.


0

Подивіться, що взагалі так погано в EAV? від Аарона Бертран для отримання деякої інформації про модель EAV.

Ймовірно, буде кращим способом мати стовпчик для кожного типу даних, а не XML або кілька таблиць.

Частина обмеження проста:

CHECK 
(
    CASE WHEN col1 IS NOT NULL THEN 1 ELSE 0 END + 
    CASE WHEN col2 IS NOT NULL THEN 1 ELSE 0 END + 
    CASE WHEN col3 IS NOT NULL THEN 1 ELSE 0 END = 1
)

На цьому сайті є багато існуючих питань та відповідей , і, ймовірно, інші, де запитувач не знав використовувати цей термін у своєму питанні.

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

Відповідь на основі коментарів на запитання, залишені Аароном Бертрандом


-1

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

Я б поїхав з NVARCHAR (MAX), а потім просто дозволити фронтенд займатися зберіганням / завантаженням вмісту. Можливо, бітове поле IS_CORRECT, де інтерфейс може зберігатися, якщо відповідь правильна.

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