質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.49%
Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Q&A

解決済

3回答

1594閲覧

アンケートアプリを作成中。DB設計で躓いてしまいました。。。

west_side_park

総合スコア45

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

0グッド

0クリップ

投稿2019/04/23 09:53

前提・実現したいこと

Railsで、学生たちに国語・数学・理科・社会・英語の習熟度をラジオボタンを使って0~5段階でチェックしてもらうアプリを作成しようとしています。

躓いていること

DB設計で躓いてしまい、お力をお借りしたいです。
今回、例えば数学であれば、

イメージ説明

このように、大項目の下に中項目、中項目の下に小項目、というような形式です。
これが残り4教科分あります。
加えて、最後にアンケート欄を設けます。

考えてみたテーブル設計

■ Userテーブル
name:string
password:string
あとadminなど追加、、、

■ Questionテーブル
user_id:integer ← 誰の回答なのかを管理するため
description:text ← 冒頭の説明文

■ FirstClassテーブル(大項目)
first_title:text ← 大項目の名称(数学)

■ SecondClassテーブル(中項目)
second_title ← 中項目の名称(数Ⅰ、数A)
first_class_id:integer ← どの大項目に属するかを管理するため

■ ThirdClassテーブル(小項目)
third_title ← 小項目の名称(順列)
first_class_id:integer ← どの大項目に属するかを管理するため
second_class_id:integer ← どの中項目に属するかを管理するため

■ ForthClassテーブル(少々項目)
forth_title ← 小項目の名称(円順列、重複順列)
first_class_id:integer ← どの大項目に属するかを管理するため
second_class_id:integer ← どの中項目に属するかを管理するため
third_class_id:integer ← どの小項目に属するかを管理するため

■ Answerテーブル
user_id:integer ← 誰のアンケートなのかを管理するため
first_class_id:integer ← どの大項目に属するかを管理するため
second_class_id:integer ← どの中項目に属するかを管理するため
third_class_id:integer ← どの小項目に属するかを管理するため
forth_class_id:integer ← どの少々項目に属するかを管理するため
coice_number:integer ← 回答番号

今回のような少し複雑な表をデータベースにするとき、このような考え方で合っていますでしょうか??

初歩的な質問かもしれませんが、どうぞよろしくお願い致します。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

質問文にある表の形をそのまま DB にするので十分では?

User テーブル id, name, password, ... Category テーブル id, 教科名, 項目名1, 項目名2, 項目名3, 項目名4, 項目名5 Answer テーブル id, user_id, category_id, 回答

Category テーブ中の文字列の重複記載が気になるなら、

名前 テーブル id, 名前

として、Caeroby てテーブルに 名前_id を記載するようにすればよいです。

親子関係のリンクをレコードに持つ方法は柔軟性はありますが、質問文にあるような形式の表示を組み立てようとする際に苦労する気がします。

投稿2019/04/23 14:28

katoy

総合スコア22324

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

west_side_park

2019/04/23 14:56

ご回答ありがとうございます。非常に分かりやすいです。 頭でっかちに大項目、中項目、小項目などを別のテーブルで考えていたのですが、 表の1行をカテゴリーテーブルのレコードとして扱えばよいということですね。 こういう風になるという認識ですが合っていますでしょうか? Categoryテーブル レコード1[[id:1],[教科:数学][項目1:数ⅠA][項目2:数Ⅰ][項目3:数と列][項目4:null] レコード2[[id:2],[教科:数学][項目1:数ⅠA][項目2:数Ⅰ][項目3:論理と集合][項目4:null] レコード3[[id:3],[教科:数学][項目1:数ⅠA][項目2:数A][項目3:順列][項目4:円順列] ... この形であれば、管理者が質問項目を追加しようとしたとき、項目1,2,をセレクトボックスから引っ張ってきて項目3を手打ちで入力するなど柔軟に対応できそうです。
katoy

2019/04/23 22:24

はい、そういう感じです。 さらに 表示するときの順番を保持する列を Categoryテーブル に追加するとよいかもしれません。(名前テーブルの方に順番列を追加する案もかんがられますが、まずはcategy 列が select したときに 人間の直感に近いかたちで表示できるようにしておいたふが開発をしやすいです) ある程度動作しだして要件も固まってきてから、改めてDB構造の正規化をすすめれば良いと思います。
west_side_park

2019/04/24 06:49

ちょうど、レコードの取り出し方を悩んでるところでした。 each文でレコードを上から順に取り出そうとした場合、あとで追加した質問項目が最後に取り出され、任意の場所に配置することができないですよね。。。 katoy様がおっしゃる、表示する順番を保持するというができると解決すると思うのですが、具体的にイメージできません。すみませんが、もう少しだけアドバイスお願い致します。
katoy

2019/04/24 12:19

順序列 (int) を追加します。(例えば order_disp) select するときに order by 'order_disp' ASC のようにして 昇順で並べるように指定します。新たなカテゴリーを挿入したときは, レコードの ID は一番大きいものになってしまいますが、 order_disp 列の値を付け直す事で好きな位置へ挿入したように表示させることができます。
west_side_park

2019/04/24 14:48

なるほど。カテゴリを生成するときに問1、問2みたいな感じのカラムも入力できるようにして、それを表示順に見立てるということですね。自分でも調べてみますが、例えば1~10まで作成していて、7と8の間に追加したいときに順序列(int)は8で入力すると元の8、9、10は一つずつずれて表示できますか?
katoy

2019/04/24 20:55

disp_order の値が同じ値の列が複数あった場合、それら行の順序は不定です。 確実に順序よくとりだせるようにするためには次のようにします。 7 と 8 の間にレコーを追加するときはそのレコードの disp?order は 8, 既存レコードの order_disl 8, 0, 10 のものはそれぞれ 9, 10, 11 と値を更新してやるのdす。 値お更新作業が面倒なら、 disp_order を double にしておrき、 追加するレコードの disp_ordr を 7.5 にするなら、他のレコーdの disp_order 更新は不要になります。 あるいは、 disp_order を 6 100000, 2000000 の用に間隔もった値を最初に設定しておけば。 150000 で間へ村有することができます。
west_side_park

2019/04/25 00:47

今回は、表示の仕方を項目順で考えていてeach文で取り出すにしても難しいなぁ、、、と悩んでいたので、Katoy様のご指摘でかなりイメージができてきました!テーブルの数自体はそんなに多くないので、一旦これで実装に入りつつ、不都合があればその時に設計を考え直してみます。 私は私立中学の教師なのですが、情報系の大学を出たというだけでなぜか急に、生徒が使うこのアプリを作るように命じられ焦っておりました… 一応期限が5月中旬なのでGWも使えば何とかと思っていますが、また煮詰まった時にぜひ相談させてください。ありがとうございました!
katoy

2019/04/25 12:13

> ... 情報系の大学 ... 期限が5月中旬 ... 無謀な指示としかおもえません、生徒の親・兄弟でにプログラミングができるかたがいれば、そのかたに対価を払ってつくってもらったほうがよいのでは?
west_side_park

2019/05/01 05:20

新しい教頭が意識だけ高い系みたいな感じでして、生徒がプログラミングに興味を持つキッカケにもなりますからお願いしますってことでした…。もう職員の間で決定事項のような感じだったらしく、断るすきもなく引き受けてしまいました。しっかり断ればよかったのですが、受けてしまった以上、やるしかないって感じです。。。
guest

0

「Aさんの重複順列が2点」
という情報がわかれば
「重複順列は順列に属する」
「順列は数Aに属する」
「数Aは数IAに属する」
「数IAは数学に属する」
と遡れますよね。
質問のケースでは一つ一つのテーブルが自分の親を参照するだけで十分なはずです。

仮に質問に記載されているように一番下の項目がすべての上位項目に対して「どこに属するか」と指定を入れた場合、「重複順列は数IAに属し、英語に属する」かつ「数IAは数学に属する」という矛盾が発生してしまう可能性を含んでしまい、データの整合性が担保できなくなってしまいます。

投稿2019/04/23 11:27

mather

総合スコア6753

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

west_side_park

2019/04/23 13:26

ご回答ありがとうございます。非常に分かりやすいご指摘で、頭の整理ができました。 それぞれのテーブルが自分の親を参照するだけで遡れるのは分かりましたが、回答を保管するAnswerテーブルは、自分の親になるテーブルが中項目の時もあれば小項目のときもあるので、親になる可能性のある項目のidを持っておくという認識は合っていますでしょうか?
mather

2019/04/23 14:45

点数それぞれが1レコードになるので、点数を格納する単位にまずは粒度を合わせたほうがいいと思います。 僕だったら、「数と列」「円順列」は同じテーブルに格納して、その親はそれぞれ「数と列」「順列」にすることで、親子が同じ名前になる場合は中間が分岐していないだけだと解釈すればいいのではないでしょうか。
west_side_park

2019/04/23 15:02

返答ありがとうございます。 >「数と列」「円順列」は同じテーブルに格納して、その親はそれぞれ「数と列」「順列」にすることで、親子が同じ名前になる場合は中間が分岐していないだけ というのが少し難しいのですが、整理して考えさせていただきます!
mather

2019/04/23 15:37

数学 -> 数1A -> 数A -> 順列 -> 円順列 -> Aさんが2点 に対して 数学 -> 数1A -> 数1 -> 数と列 -> 数と列 -> Aさんが2点 とみなせば同じ階層の数で表現できますよね?
mather

2019/04/23 15:42

ちなみに、「Aさんが2点」と言っても2つの値の意味(「数と列」、「円順列」の点数)は違うのでデータベース上は親IDが違って同じレコードにはなりませんし、 同じ「数と列」であっても、違う階層を表現しているものなのでデータベース上はテーブルが分かれるため同じものではありません。
west_side_park

2019/04/24 06:29

「数と列」と「円順列」を同じ階層で考えるということの意味が分かりました。個人的に、親子で名前が同じになるケースを考えるとややこしく感じるので、以下のテーブル設計で進めてみようと思います。 Category(項目)テーブル id, 教科名, 項目名1, 項目名2, 項目名3, 項目名4, 項目名5 ⇒(項目名3, 項目名4, 項目名5はnullの場合もある) Answer テーブル id, user_id, category_id, 回答 非常に分かりやすい指摘をいただきましてありがとうございます! また考えが詰まったとき、ご助力いただけますと嬉しいです。
guest

0

DBの設計について一番単純なデータ保持の仕方は
「隣接リストモデル」すなわち、自分のIDを持ち、自分の親のIDを持つ方法

SQL

1create table tbl(id int primary key,pid int null,name varchar(20),endflg tinyint); 2insert into tbl values 3( 1,null,'数学',0), 4( 2, 1,'数IA',0), 5( 3, 2,'数I',0), 6( 4, 3,'数と列',1), 7( 5, 3,'論理と集合',1), 8( 6, 3,'2次関数',1), 9( 7, 2,'数A',0), 10( 8, 7,'場合の数と確率',1), 11( 9, 7,'順列',0), 12(10, 9,'円順列',1), 13(11, 9,'重複順列',1), 14(12, 1,'数IIB',0), 15(13,12,'数II',0), 16(14,13,'式と証明',1), 17(15,13,'複素数と方程式',1), 18(16,13,'図形と方程式',1), 19(17,12,'数B',0), 20(18,17,'平面ベクトル',1), 21(19,17,'空間ベクトル',1);

endflgは最終データかどうか(別になくてもよい)

  • データ検出

SQL

1select * from tbl as t1 2left join tbl as t2 on t1.id=t2.pid 3left join tbl as t3 on t2.id=t3.pid 4left join tbl as t4 on t3.id=t4.pid 5left join tbl as t5 on t4.id=t5.pid 6where t1.pid is null 7order by t1.id,t2.id,t3.id,t4.id,t5.id 8

※この場合データの保持が冗長なため
ネストが最大いくつになるかをわかっていないと調べられません。

これを更に効率よく管理するには「入れ子集合モデル」という
データ保持の仕方が必要です。
このモデルの場合、データがインタラクティブに変化していくため
プロシージャという仕組みで随時データを書き換える必要がでてきますので
もし興味があるようなら聞いてください

投稿2019/04/23 10:50

yambejp

総合スコア114757

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

west_side_park

2019/04/23 13:32

ご回答ありがとうございます。プロシージャという単語は初めて聞きました。SQLもまだ全然なレベルなので時間がかかるかもしれませんが、丁寧にご回答いただいたのでしっかり調べたいと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.49%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問