在数据库中存储多项选择调查答案的最佳方式

时间:2013-02-06 22:57:58

标签: mysql sql database

我目前正在使用PHP / MySQL开发调查创建/管理Web应用程序。我已经经历了数据库表的几个修订,我再次发现我可能需要重新考虑某种类型答案的存储。

现在,我有一个看起来像这样的表:

survey_answers

id          PK
eid
sesid
intvalue    Nullable
charvalue   Nullable
  

id =分配给每一行的唯一值

     

eid =调查问题,这个答案是回复

     

sesid =调查'会话'(有关调查时间和日期的信息)id

     

intvalue =答案的值,如果它是一个数值

     

charvalue =答案的值,如果它是文本表示

这使我能够继续使用MySQL的数学函数来加速处理。

然而,我发现了一个新的挑战:存储有多个回复的问题。 一个例子是:

您喜欢吃以下哪种食物? (选择所有申请)

  • 女童子军饼干
  • 培根
  • 玉米
  • 鲸鱼脂肪

现在,当我想存储结果时,我不确定处理它的最佳方法。 目前,我有一个表格可供选择,如下所示:

survey_element_options

id        PK
eid
value
  

id =与每行相关联的唯一值

     

eid =此选项与

关联的问题/元素      

value =该选项的文本值

通过此设置,我将返回的多个选择答案存储在'survey_answers'中,作为在调查中选择的element_options行的逗号分隔ID的字符串。 (例如“4,6,7,9”之类的东西)我想知道这是否确实是最好的解决方案,或者如果创建一个能够容纳每个答案的新表更为实际,然后再参考给定的答案行反过来引用回到元素并最终引用调查。


修改

对于任何有兴趣的人,这是我最终采取的方法(在PhpMyAdmin Relations View中):

Database Relationships and Table Structure

收集多选问题的计数的基本查询将如下所示:

SELECT e.question AS question, eo.value AS value, COUNT(eo.value) AS count
FROM survey_elements e, survey_element_options eo, survey_answer_options ao
WHERE e.id = 19
AND eo.eid = e.id
AND ao.oid = eo.id
GROUP BY eo.value

4 个答案:

答案 0 :(得分:4)

这真的取决于很多事情。

  1. 通常,在数据库中存储逗号分隔值列表是不好的,特别是如果您计划对该数据进行远程智能化操作。特别是如果您想对答案进行任何类型的高级报告。
  2. 最佳关系存储方法是在第二个表中定义答案,然后将它们链接到用户对第三个表中问题的响应(每个用户问题有多个条目)或者可能是用户调查问题,如果用户可以使用相同的问题进行多次调查。
  3. 作为一个简单的例子,这可能会稍微复杂一些:

    示例表:

    • UsersUsernameUserID
    • QuestionsqIDQuestionsText
    • AnswersAnswerText [在这种情况下示例可以重复使用,但这确实会造成额外的复杂层],aID
    • Question_Answers([此问题的可用答案,每个问题多个条目] qaIDqIDaID),
    • UserQuestionAnswersqaIDuID

    注意:仅作为示例,而不是推荐

答案 1 :(得分:0)

将主键转换为非唯一索引,并在相同的ID下为同一问题添加答案。

例如。

id  | eid | sesid | intval | charval
 3     45      30        2  
 3     45      30        4

如果需要,您仍然可以为常规唯一PK添加另一列。

保持简单。这里不需要关系。

答案 2 :(得分:0)

真的是课程的马匹。

您可以存储为逗号分隔的字符串(但是当您在其中一个答案中使用文字逗号时会发生什么情况。)

您可以存储为一对多表格,例如:

survey_element_answers

id                PK
survey_answers_id FK
intvalue          Nullable
charvalue         Nullable

然后遍历该表。如果您选择了一个答案,则会在此表中创建一行。如果您选择两个答案,它将在此表中创建两行,等等。然后,您将从survey_answers表中删除intvalue和charvalue。

另一个选择,因为你已经在他们自己的表中存储元素选项,就是创建一个多对多表,例如:

survey_element_answers

id                         PK
survey_answers_id          FK
survey_element_options_id  FK

同样,每个选项选择一行。

另一种选择是存储位掩码值。这将消除对多对多表的需求。

survey_element_options

id              PK
eid             FK
value           Text
optionnumber    unique for each eid
optionbitmask   2 ^ optionnumber

optionnumber对于每个eid应该是唯一的,并且从1开始递增。如果使用bigint,则将限制63个选项;如果使用int,则将限制为31个选项。

然后在 survey_answers

id            PK
eid
sesid
answerbitmask bigint

Answerbitmask是通过为用户选择的每个选项添加所有optionbitmask来计算的。例如,如果7存储在Answerbitmask中,则表示用户选择了前三个选项。

联接可以通过以下方式完成:

WHERE survey_answers.answerbitmask& survey_element_options.optionbitmask> 0

所以是的,还有一些选择需要考虑。

答案 3 :(得分:-1)

如果您不在另一个查询中将id用作外键,或者您可以使用sesid查询结果,请尝试多对一关系。 否则,我会将多选答案存储为序列化数组,例如JSON或通过php的serialize()函数。