複数の異なる型である可能性のある値を格納する適切な方法


11

私が持っている回答のテーブルと質問表を。

回答のテーブルには、値を持っていますが、問題によっては、この値は以下のようになりbitnvarcharまたはnumber(今のところ)。質問は、その意図した回答値の型がどうあるべきかという概念を持っています。

少なくとも数値を比較する必要があるため、これらのAnswer値をどこかで解析することが重要です。

もう少しコンテキストについては、質問と潜在的な回答(通常、テキストボックスタイプの入力に許可されているデータタイプ)は、ソートの調査で一部のユーザーによって提供されます。その後、指定された他のユーザーが回答を提供します。

私が検討したいくつかのオプションは次のとおりです。

A.目的のタイプに応じて異なる方法で解析されるXMLまたは文字列(質問で追跡されます)

B. Answerテーブルを参照する(またはAnswerテーブルによって参照される)3つの個別のテーブル。意図されたタイプに基づいて結合されます。この場合、各質問の回答が1つだけになるように制約を設定する最善の方法、またはそれをアプリケーションに任せる必要があるかどうかはわかりません。

C.目的のタイプに基づいて取得できるAnswerテーブルの3つの個別の列。

私はこれらのアプローチの長所と短所、または私が考慮していなかった代替のアプローチについていくつかの情報を得ていただければ幸いです。

回答:


2

それは本当にあなたのフロントエンドがデータにアクセスする方法に依存します。

O / R-mapperを使用している場合は、データベースの設計ではなく、クラスのオブジェクト指向の設計に焦点を当ててください。その後、データベースはクラス設計をミラーリングします。正確なdb設計は、使用しているO / R-mapperおよび継承マッピングモデルによって異なります。

レコードセット、データテーブル、データリーダーなどを介してテーブルに直接アクセスしている場合、簡単なことは、インバリアントカルチャを使用して値を文字列に変換し、それを単純なテキスト列に格納することです。 。そしてもちろん、値を読み取るときにテキストを特殊な値の型に戻すために、同じカルチャを再度使用します。

または、値タイプごとに1つの列を使用できます。今日、テラバイトのドライブがあります!

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テーブルに挿入されます。質問に回答する2番目のユーザーは、回答のリストから選択します(true / false = 2つのリスト)。PollQuestionテーブルを展開して、作成した質問を追跡するために、必要に応じて作成者のユーザーIDを含めることもできます。

UIでは、ユーザーが選択した回答をPollOptionId値に関連付けることができます。PollQuestionIdと一緒に使用すると、回答が質問に対して有効であることをすばやく確認できます。有効な場合の応答は、PollResponseテーブルに入力されます。

ユースケースの詳細に応じて、いくつかの潜在的な問題があります。最初のユーザーが数学の質問を使用したいが、複数の可能な答えを提供したくない場合。別の状況は、最初のユーザーが提供するオプションが、2番目のユーザーが選択できる唯一のオプションではない場合です。これらの追加のユースケースをサポートするために、次のようにこのスキーマを作り直すことができます。

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のさまざまなデータ型を処理できます。残念ながら、私たちは完璧な世界に住んでいません。私が考えることができる最良の妥協案は、PollQuestionテーブルでAlternateResponseデータ型を指定し、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テーブルから選択することで、質問作成者が使用できるすべてのデータ型をリストできます。UIはQuestionDataTypeIdを参照して、代替応答フィールドの適切な形式を選択できます。TSQLデータ型に限定されないため、「電話番号」をデータ型にすることができ、UIで適切なフォーマット/マスキングを取得できます。また、必要に応じて、単純なcaseステートメントを使用してデータを適切なタイプにキャストし、代替の回答に対してあらゆる種類の処理(選択、検証など)を実行できます。


0

とにかく、EAVの何がそれほど悪いのか見てくださいEAVモデルに関する情報については、Aaron Bertrandによる。

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
)

このサイトには、タグが付けられた既存の質問と回答が多数あります。おそらく、質問者が質問でその用語を使用することを知らなかった人もいます。

それらはすべての長所と短所をカバーする可能性が高いため、これらを一読することを強くお勧めします(これにより、実際には変更されていない場合でも、ここでそれらを再度ハッシュすることはできません)。

Aaron Bertrandが残した質問のコメントに基づく回答


-1

私は問題があまりにも多くの考えを与えられているか、特定の回答が他の回答よりも順応性があるかもしれない理由にいくつかの追加の制約があると思います。現在、回答がDBによって何らかの方法で処理される必要があるという証拠はないようですが、ログフィールドとしてのみです。

私はNVARCHAR(MAX)を使用して、フロントエンドにコンテンツの格納/取得を処理させます。回答が正しければ、フロントエンドが格納できるIS_CORRECTビットフィールドである可能性があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.