web-dev-qa-db-ja.com

PHPおよびMySQLを使用して「クイズ」Webアプリケーションを開発するためのデータベース設計

したがって、私はPHPとMySQLを学習しようとしています(両方の基本的な理解があります。HeadFirst SQLとHead First PHP&MySQL)と私は私の知識を固めるための最良の方法は、読むのではなく何かを構築することです。

それを念頭に置いて、サーバー上のMySQLデータベースに接続する基本的なWebページを作成したいと思います。基本的なHTMLフォームを作成し、ユーザーがlast_name、first_name、Eメール、誕生日、性別などの基本情報を入力できるようにします。

私の問題は基本的なクイズの結果を記録するデータベースを設計する方法がわかりません-5つの多肢選択問題だけが必要です。最終的に、ユーザーの結果と以前のユーザーの結果を表示したいと思います。

5問のクイズのテーブルの設計方法を理解していただけると助かります。ありがとう!

21
Abundnce10

4つの単純なテーブルから始めます。

 * User
   - user_id    auto integer
   - regtime    datetime
   - username   varchar
   - useremail  varchar
   - userpass   varchar
 * Question
   - question_id   auto integer
   - question      varchar
   - is_active     enum(0,1)
 * Question_choices
   - choice_id        auto integer
   - question_id      integer
   - is_right_choice  enum(0,1)
   - choice           varchar
 * User_question_answer
   - user_id      integer
   - question_id  integer
   - choice_id    integer
   - is_right     enum(0,1)
   - answer_time  datetime

このテーブルデザインに関する私の考えは次のとおりです。

  • テーブルUserは、登録済みユーザーを格納するためのものです。
  • テーブルQuestionは、すべての質問を格納するためのものです。 is_activeがあるため、アクティブな質問のみを選択的に表示できます(WHERE is_active = '1'を使用)
  • テーブルquestion_choicesは、使用可能なすべてのオプションを格納するためのものです。 is_right_choiceがあり、特定の質問に対する正しい答えがどの選択肢であるかを定義します。
  • テーブルUser_question_answerは、ユーザーからの回答を格納するためのものです。検索を高速化するためのis_rightがあり、特定の質問と回答の選択が正しいかどうかを確認します(以前に定義されたis_right_choiceに基づく)。また、特定のユーザーが質問に答えたときに注意するためのanswer_timeもあります。
38
ariefbayu

プログラミングの一般的な知識はわかりませんが、始めたばかりの場合でも、フレームワークを使用することをお勧めします。

フレームワークを使用すると、プロジェクトに必要なツールのベストプラクティスの実装が提供されます。

私は個人的に Symfony をphpプロジェクトに使用しています。 それらのガイドとチュートリアル を確認することをお勧めします。 symfonyは定評のあるフレームワークであり、広く受け入れられている設計に基づいています。

しかし、あなたの質問にもっと直接答えるために、私はあなたのアプリケーションのためにこのようなものを提案するでしょう:

 - user
  - id (PK)
  - last_name
  - first_name
  - email
  - gender


 - quiz
  - id (PK)
  - title


 - quiz_question
  - id (PK)
  - quiz_id (FK)
  - text

 - quiz_question_option
  - id (PK)
  - quiz_question_id (FK)
  - text
  - is_correct

 - quiz_user_answer
   - id (PK)
   - quiz_question_id (FK)
   - quiz_question_option_id  // this is the answer.

上記により、複数の質問を持つ複数のクイズを定義し、回答セット(クイズに対するユーザーの回答セット)を作成して、各回答を記録できます。

それが役に立てば幸い:)

10
SuitedSloth

これは、約8年前にPHP/MySQLで最初に行ったプロジェクトでもあります。

最初の解決策は、フォームと完全に一致するようにデータベースをコーディングすることです。したがって、ユーザーとクイズの提出を記録したいので、次のようになります。

CREATE TABLE users (
  username VARCHAR(16) PRIMARY KEY, 
  password VARCHAR(8), 
  email VARCHAR(255), 
  birthday DATE, 
  gender ENUM('M', 'F')
);

CREATE TABLE quiz_answers (
  username VARCHAR(16) REFERENCES users,
  question1 VARCHAR(10),
  question2 INT,
  question3 ENUM('YES', 'NO', 'MAYBE'),
  question4 BOOLEAN,
  question5 VARCHAR(25),
  submitted_at DATETIME,
  PRIMARY KEY (username, submitted_at)
);

したがって、これは最低限必要なこと、つまりユーザーとクイズの提出を記録しているだけです。実際のクイズに合わせて作成する必要がある回答のタイプを示しました。また、ユーザーからの応答と、ユーザーが送信した瞬間の応答も作成しました。代理キー(AUTO_INCREMENT)を使用する可能性が高くなりますが、私は代理にできるだけ抵抗したいと思っています。

すぐに1NF違反があります:questionN。これを正しく行う場合は、これらの列に、どの質問であるかだけでなく、その意味を示す名前を付けます。しかし、これを正規化することは、拡張可能で履歴を追跡するフォームへの次のステップです。

したがって、次に気付くのは、実際のクイズは質問のコレクションであり、それぞれに可能な回答のコレクションがあることです。そして、フォームの送信は、特定のクイズユーザーによる、特定のクイズフォームでの質問に対する選択された回答のセットを実際に関連付けます。これは、ユーザー、クイズ、質問、回答という4者間の関係のように聞こえます。異なるクイズで質問を繰り返してもかまわない場合は、そのうちの1つを削除できますが、完全を期すために、この道を進みましょう。上記のquiz_answersをこれに置き換えます。

CREATE TABLE questions (
  id INTEGER AUTO_INCREMENT PRIMARY KEY,
  question TEXT
);

CREATE TABLE answers (
  id INTEGER AUTO_INCREMENT PRIMARY KEY,
  question_id INTEGER REFERENCES questions,
  answer VARCHAR(255)
);

CREATE TABLE quizzes (
  name VARCHAR(255) PRIMARY KEY,
);

クイズ用の特別なメタデータは実際にはないので、今のところ名前にすぎません。

したがって、今、あなたは質問から回答へ、そしてクイズから質問への一対多の関係が必要です。

CREATE TABLE question_answers (
  question_id INTEGER REFERENCES questions,
  answer_id INTEGER REFERENCES answers,
  idx INTEGER,
  PRIMARY KEY (question_id, answer_id)
);

CREATE TABLE quiz_questions (
  quiz_name VARCHAR(255) REFERENCES quizzes,
  question_id INTEGER REFERENCES questions,
  idx INTEGER,
  PRIMARY KEY (quiz_name, question_id)
);

上記のように注意が必要な部分は、ユーザーとフォーム送信の間のより高次の関係、およびフォームの質問からユーザーの回答へのリンクです。繰り返しを避けるために、これを2つのテーブルに分けることにしました。

CREATE TABLE quiz_submissions (
  id INTEGER AUTO_INCREMENT PRIMARY KEY,
  username VARCHAR(16) REFERENCES users,
  quiz_name VARCHAR(255) REFERENCES quizzes,
  submitted_at DATETIME
);

CREATE TABLE submission_answer (
  submission_id INTEGER REFERENCES quiz_submissions,
  question_id INTEGER REFERENCES questions,
  answer_id INTEGER REFERENCES answers,
  PRIMARY KEY (submission_id, question_id)
);

この時点では、これはかなりよく正規化されています。また、クエリを実行するのが少し難しくなることもわかります。クイズのすべての質問を出すには、クイズから質問に参加する必要があります。そこから回答に参加して1つの大きなクエリを実行し、フォームを作成するために必要なすべてのデータを取得するか(さらに後処理を行う必要があります)、各質問に対してデータベースにもう一度アクセスして実行することができます後処理が少ない。私はどちらの方法でも議論できます。特定のユーザー全員の回答を得るには、クイズIDとユーザー名を含むuser_submissionsから、ユーザーが選択した質問と回答へのsubmission_answerテーブルへの選択を行う必要があります。したがって、クエリはすぐに興味深いものになります。参加している場合、参加への恐怖を失うことになります。

これにより、リレーショナルデータベースをあまり使いこなさないようにしてください。これを行うと、制限された形式ではありますが、実際には、リレーショナルモデル内でリレーショナルモデルを実行することになります。

私が上記で行ったような多くの自然なキーを使用することは、今日では少し正統ではないことに気づきました。ただし、1〜10の範囲のすべての整数ではない場合に、結合がどのように機能するかを簡単に確認できるため、少なくとも開始時に試してみることをお勧めします。

5
Daniel Lyons

さて、私は現在開発段階にあり、まだいくつかの問題(つまり、サーバーとクライアント間のラウンド状態の同期)が発生しますが、多少の助けになるかもしれません enter image description here

PS:上の図のように、データベースにパスワードを保存しないでください-代わりにパスワードのハッシュを保存してください

2
Artem Zaytsev