何时分离数据库列含义(通用列)

时间:2016-02-15 12:29:16

标签: database database-design relational-database

我正在为一个有大约20个问题的网站设计一个反馈系统,但这些问题可能会每年都有所改变,并试图考虑最佳设计。

最简单的方法是将每个问题映射到一列,但这需要每年创建一个新表并更改根本不合理的应用程序代码。

第二种选择是将列与含义分开,并使用第二个应用含义的表,即

Table1: (row per survey)  Table2: (row per questionnaire type)
QuestionID                AnswerID
Question1                 QuestionID
Question2                 Answer1
...                       ....  
Question20                Answer20   

我能想到的第三个选择是将每个方面完全分开,如:

Table1:       Table2:     Table3:       Table4:
QuestionID    AnswerID    MatchTableID  SetID
QuestionValue AnswerValue QuestionID    FeedbackSet
                          AnswerID      QuestionID

这给了它可扩展性的好处,但是对于几百条记录而言,每年最多更改一次的内容可能会过多,而且我不确定它是否感觉有点像实体属性 - 价值设计。

我很感激对这里被认为是最佳做法以及被认为是可接受的做法的任何评论。

1 个答案:

答案 0 :(得分:2)

您可能希望保持简单并使用经典的关系设置。

模特:

class Question < ActiveRecord::Base
  has_many :replies
  has_many :answers
  belongs_to :questionnaire
end

class Answer < ActiveRecord::Base
  belongs_to :question
  has_many :replies
end

# A collection of questions
class Questionnaire < ActiveRecord::Base
  has_many :questions
  has_many :replies, through: :questions
end

# A user reply to a question
# acts as a many to many join table
class Reply < ActiveRecord::Base
  belongs_to :question
  belongs_to :answer
end

架构:

ActiveRecord::Schema.define(version: 20160215124045) do

  create_table "answers", force: :cascade do |t|
    t.text     "text"
    t.integer  "question_id"
    t.datetime "created_at",  null: false
    t.datetime "updated_at",  null: false
  end

  add_index "answers", ["question_id"], name: "index_answers_on_question_id"

  create_table "questionnaires", force: :cascade do |t|
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

  create_table "questions", force: :cascade do |t|
    t.text     "text"
    t.integer  "questionnaire_id"
    t.datetime "created_at",       null: false
    t.datetime "updated_at",       null: false
  end

  add_index "questions", ["questionnaire_id"], name: "index_questions_on_questionnaire_id"

  create_table "replies", force: :cascade do |t|
    t.integer  "question_id"
    t.integer  "answer_id"
    t.datetime "created_at",  null: false
    t.datetime "updated_at",  null: false
  end

  add_index "replies", ["answer_id"], name: "index_replies_on_answer_id"
  add_index "replies", ["question_id"], name: "index_replies_on_question_id"

end

是的,它有很多表 - 但是这给了你很大的灵活性,而不用处理关键值表的麻烦。而且它的构建速度要快于对动态模式的一些hacky尝试。

如果需要,它也很容易拉出指标。

这个例子做了很多假设:

  • 问题是多种选择 - 不写入。您可以通过将回写表存储在回复表中来简单地调整它。
  • 问题与问卷之间的关系是一对一的。如果需要能够在多个问卷上重复使用问题,请使用联接表和HABTM关系或has_many through: