【问题标题】:Database Design: Flexible Storage of Q&A数据库设计:问答的灵活存储
【发布时间】:2011-05-23 02:28:09
【问题描述】:

我有一段时间没有设计数据库了,我现在对自己的设计没有太大的信心。我基本上在数据库中有三个表,它们代表各种历史。我必须更改此系统,以便每次添加记录(例如,某些内容成为历史记录)时,可能需要用户的一些输入。有时他们只会提出一个简单的问题,有时他们会被要求提供五种不同的信息,这些信息需要由最终用户通过管理前端进行灵活管理。所以我计划有一个问题表和答案表,用复合表将它们与其他三个表联系起来。我正在努力设计答案表,因为每个问题都可能需要各种回答。一些响应将是通过外键绑定到另一个数据库的下拉选择。其他可能是文本输入、日期或是/否答案。现在,我有一个答案表,其中包含所有类型的答案以及一系列可为空的字段...

+----------------------------+
| Answer                     |
+----------------------------+
| Id (int)                   |
| QuestionId (int)           |
| ForeignKeyId1* (int)       |
| ForeignKeyId2* (int)       |
| ForeignKeyId3* (int)       |
| Number* (bigint)           |
| DateField* (date)          |
| Text* (varchar 500)        |
| YesNo* (bit)               |
+----------------------------+
  *Nullable

旁注:问题表与 QuestionType 相关联,该 QuestionType 将指示(在应用程序内)如何验证用户输入。输入存储在 Answer 记录中相应的可为空字段中,而其他字段为空。我认为这比没有数据完整性的 catch all varchar 答案字段要好。

这是一个糟糕的设计吗?有什么可以让它变得更好?

【问题讨论】:

    标签: database-design relational-database


    【解决方案1】:

    根据您的描述,您的解决方案看起来应该可以正常工作。我已经对设置了列以记录特定类型的数据的表进行了类似的设置,从而允许其他字段可以为空。对我来说看起来不错,虽然我不确定您的 ForeignKeyID 字段的用途:\

    【讨论】:

    • ForeignKeyId 字段用于用户将从下拉列表中选择的答案。它们与其他桌子相连。感谢您的反馈:)
    • 嗯,好的。不是要详细说明您要做什么,而是您是否考虑过制作另一个答案 ID 和问题 ID 表。这样你就可以得到尽可能多的有效答案。目前,如果您想为任何问题添加另一个有效答案,您会遇到问题。只是一个建议:) 希望一切顺利。
    • 已经实现了,但它与手头的问题并不真正相关;)
    【解决方案2】:

    为不同的数据类型设置不同的字段是可以的,就像拥有多个外键一样。这种设计将尽可能多的数据域完整性推入 DBMS。从哲学上讲,这是一个好方法,因为大多数人会告诉您,让 DMBS 为您完成工作将节省您编写和维护代码的时间。大多数时候我都会是那些人中的一员。

    从可维护性的角度来看,还有另一种方法。就目前而言,如果您添加了一种新的数据类型,例如浮点数或 GUID,您将不得不返回并修改 ANSWER 表的结构。同样,如果您提出另一个需要从新查找表中获得答案的问题类型,则必须返回并添加另一个 FK 字段。

    您可以更改您的 ANSWER 表以使用包罗万象的方法,使其看起来更像这样:

    ANSWER
    ( Id (int)
    , QuestionId (int)
    , Part (int)
    , Value (nvarchar 1000)
    )
    

    如果我正确理解了您的问题,那么一个问题可能会有多个部分的答案。假设一个问题可能有多个答案,并且您的问题控制表知道哪个部分是哪个部分,您将使用 Part 字段来区分这些部分。如果每个问题恰好有零个或一个答案,则不需要答案表,只需将答案添加到问题中即可。

    那么,您为什么要放弃让数据库强制执行数据域完整性?以下是相对的优缺点:

    多个独立答案字段的优点:

    • DBMS 不会让您将错误类型的数据放入字段中,因此您无需在存储数据之前编写或调用任何数据域完整性函数(除非您想在 GUI 级别捕获这些错误)
    • 对于如何解释答案的内容没有混淆(例如,这个日期答案中的月份和日期......)

    Catch All 答案字段的优点:

    • 您不必编写额外的代码 查看问题类型以找出答案 ANSWER 表中的哪一列 阅读任何给定类型的问题。
    • 您不必更改您的 数据库模式/物理数据库 每次新查找时的人口 添加了表格或答案数据类型。

    在任何一种情况下,您都必须编写一些代码来处理这样一个事实,即您将多个问题的语义不同的答案存储在一个数据存储中。您必须决定要编写哪种类型的额外代码,确定在哪里放置并找到每种类型答案的那种类型,或者确定如何使用通用表示(即字符串)存储和解释不同数据类型的那种类型)。

    鉴于修改包含数据的表是一件痛苦的事,并且鉴于大多数编程语言都内置了相当强大的 .ToString() / .TryParse() 类型功能,我倾向于使用包罗万象的方法如果我主要关心的是可维护性。

    【讨论】:

    • 非常感谢您提供这个答案!
    猜你喜欢
    • 1970-01-01
    • 2012-03-04
    • 2021-09-24
    • 2010-10-08
    • 2022-01-07
    • 2012-03-22
    • 1970-01-01
    • 2012-01-11
    • 1970-01-01
    相关资源
    最近更新 更多