正确的存储值的方式可能是多种不同的类型


11

我有一个答案表和一个问题表。

答案表中有值,但根据问题,这个值可以是一个bitnvarcharnumber(到目前为止)。该问题具有其预期答案值类型应为什么的概念。

在一个或另一个点解析这些Answer值非常重要,因为至少需要对这些数字进行比较。

对于更多情况,一些用户在各种调查中提供了问题和可能的答案(通常是文本框类型输入所允许的数据类型)。然后,其他指定的用户将提供答案。

我考虑过的几个选项是:

A. XML或字符串,根据所需的类型进行不同的解析(在问题中始终保持跟踪)

B.引用答案表(或由答案表引用)的三个单独的表,并根据预期的类型联接到其中。在这种情况下,我不确定设置约束的最佳方法,以确保每个问题只有一个答案,或者应该将其留给应用程序。

C. Answer表上的三个独立列可以根据预期的类型进行检索。

我很高兴就这些方法的优缺点获得一些意见,或者我没有考虑过的替代方法。

Answers:


2

这实际上取决于您的前端如何访问数据。

如果使用的是O / R映射器,则应专注于类的面向对象设计,而不是数据库设计。然后,数据库仅反映类设计。确切的数据库设计取决于您使用的O / R映射器和继承映射模型。

如果您是直接通过记录集,数据表,数据读取器等访问表,那么要做的一件简单的事情就是通过使用不变文化将值转换为字符串并将其存储在简单的文本列中。当然,再次使用相同的区域性,以便在读取值时将文本转换回专用的值类型。

或者,您可以在每种值类型中使用一列。今天我们有TB的驱动器!

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个列表)。如果合适,您还可以展开PollQuestion表以包括创建者的用户ID,以便跟踪他们创建的问题。

在您的UI上,用户选择的答案可以绑定到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的各种数据类型。las,我们没有生活在一个完美的世界中。我能想到的最好的折衷方法是在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到底什么不好呢?由Aaron Bertrand提供,以获取有关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
)

这个站点上有许多标记为现有问题和答案,并且可能还有其他一些提问者不知道在其问题中使用该术语的地方。

我强烈建议您仔细阅读这些内容,因为它们可能涵盖所有优点和缺点(这可以防止人们在这里将它们重新散列,而实际上他们并没有改变)。

根据Aaron Bertrand留下的问题评论进行回答


-1

我认为这个问题考虑得太多了,或者为什么某些答案可能比其他答案更容易理解,还存在其他一些限制。当前,似乎没有证据表明数据库必须以任何方式(仅作为日志字段)来处理答案。

我会使用NVARCHAR(MAX),然后让前端处理存储/检索内容。如果答案正确,则可能是IS_CORRECT位字段,前端可以在其中存储该字段。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.