マンガでよめる痔のこと・薬のこと

現在あるシステムを作成する上で、DB設計をしています。
このDB設計をする上で、多対多の状態だと良くない(できない?)とよく聞きます。

例)一人の学生は複数の講義を受講し、一つの講義には複数の学生が受講する。
この時に、学生の情報を格納する「学生DB(主キー:学生番号)」と、講義の情報を格納する「講義DB(主キー:講義番号)」を作成します。そうするとこの二つのDBの関係って、多対多になってしまうと思うのですが、この場合どのような問題が起きますか?

例がちょっとわかりにくいかもしれませが、要は
「DBを多対多の状態で設計した場合の問題点は何か?」
ということをお聞きしたいです。

よろしくお願いします。

このQ&Aに関連する最新のQ&A

A 回答 (5件)

 これ、聞いて理解できなければ、自分で困ってみるのが一番です。


 例に挙げておかれる問題は、たぶん、多対多のテーブルを直接作って構成すると、すぐにとっても困ることができるので、この場合良い事例です。

 実験をするに当たって、考慮すべき点をいくつか上げておきます。
・テーブルの設計に当たっては、現実世界の条件を満たすように構成すること。(テーブルを作っていて、「フィールドが多くなりすぎたから、講義の種類は**個しかないことにしようか」とかテーブル設計の都合で現実世界に条件を設けてはいけません。)
・現実の世界を見て、変更されそうなポイントは、容易にその変更をデータベースに反映できること。(講義の種類数が増えたから、テーブルの構成を修正するなんて言うのは、もう最悪です。これはこれで、ひとつの「困った」ですが、テーブル定義を修正すると、その後でアプリケーションを全部修正する必要があることを頭に入れておきましょう。)
・データの登録は容易にできるか、考えましょう。データを登録するために、いくつのテーブルを調査する必要があるか?ひとつのデータを登録するために、いくつのテーブルを連動して操作する必要があるか。などが考慮ポイントです。
 この際に、現実世界にあり得ないデータを登録「できない」ようになっているかも重要なポイントです。(アプリケーションでやる仕事に見えますが、これをデータベースレベルではじけるように設計するのはとても大切なことです。アプリケーションはいくつもできる可能性がありますが、データベースはひとつですから、どちらでチェックした方が確実かは自明ですね。)
・データの修正を行うときに、どれだけのテーブルとデータが関係してくるかを考えること。削除・修正の両方です。チェックポイントは挿入の時と同じです。変な操作をしたときに、データの整合性が崩れないように注意すること。あっちを修正してこっちを修正し忘れたら何が起こるかを考慮しておくのはとても重要です。へたをすると、使い物にならないデータとなり修正さえ不可能な事態に追い込まれかねないものです。

 ちなみに、最後の2点は、関係するテーブルは、できるだけ少なく構成することが吉です。多くなればなるほど、あらゆる点が複雑になっていきます。テーブルの数を少し増やすだけで操作に関わるテーブル数が減るなら、テーブルの数は増やすべきです。これをテーブル数をシンプルにしようと間違った方向に進むと先の考慮点の、登録・修正の際のデータの整合性を保証する段階で、頓挫することになります。

 この条件をクリアした時点で、データベースの設計をもう一度見てみると、たぶん、テーブルが直接多対多の関係でリレーションされていることはないでしょう。

 あえて、何故困るかは書きません。
 参考に言っておくなら、こうしたときに困らないようにデータベース理論つくられ、正規化というテクニックが生まれたのです。
    • good
    • 3
この回答へのお礼

回答ありがとうございます。

お礼日時:2008/02/03 22:56

>「なぜ作らなければならないのか?」ということがわかりません。



逆に、この中間テーブルを使わない方法を考えると
学生テーブルの方に、講義1,講義2,講義3,・・・と受講する講義のフィールド
講義テーブルの方に、学生1,学生2,学生3,・・・と受講する学生のフィールド
といった構造が考えられますが
講義のフィールド、学生のフィールドともに最大可能な数を用意する必要が有ります。
(受講する講義が少なくても、また受講する学生が少なくても常に用意する)
講義や学生の数が非常に少ないのであればこのような構造も考えられますが
数が多い場合、使われないフィールドが多く発生するために、
データベースのデータ格納効率が悪くなってしまいます。
また、受講する学生や講義をリストアップする場合も処理が複雑になります。
(フィールドが使われているかどうかの判断が必要になるので)
    • good
    • 1
この回答へのお礼

回答ありがとうございます。

お礼日時:2008/02/03 22:57

>「なぜ作らなければならないのか?」ということがわかりません。


直接は関係付けられないからということでは駄目なの?

>多対多の関係でDBを設計しても特に問題はないということでしょうか?
考える方向が逆なのでは
RDBでは現実世界の事象をテーブルという形で表現します
現実世界に多対多の関係のものがあるのですから
それを扱うDBには多対多の関係のテーブルができて当然なのでは

それとも中間テーブルというのが納得できないのかな
代表的なDBに販売というものがありますが
このケースでは顧客と商品は多対多の関係になります
従って販売テーブルが中間テーブルになります

この場合一般的には販売テーブルがメインで商品と顧客は参照先
と考え販売が中間テーブルという風には考えませんが
視点を変えればまぎれもなく中間テーブルです
    • good
    • 1
この回答へのお礼

回答ありがとうございます。

お礼日時:2008/02/03 22:58

>多対多の状態だと良くない(できない?)とよく聞きます。


どこで聞いたのか分かりませんが聞き間違いかガセです

世の中には多対多の関係になるものはいっぱい存在します

多対多の関係の場合直接は関係付けられませんから
中間テーブルを介して関係付けます

学生と講義なら

[受講テーブル](学生番号、講義番号)

というテーブルが中間テーブルになります
受講テーブルと学生が一対多
受講テーブルと講義が一対多になります

この場合のユーザーインタフェースは
講義テーブルから作った単票フォームに受講テーブルをサブフォームとしてはめ込む
ものと
学生テーブルから作った単票フォームに受講テーブルをサブとしてはめ込む
を作ればいいというのも定石ですね
    • good
    • 0
この回答へのお礼

回答ありがとうございます。

受講テーブルを作れば、多対多にならないというのはわかっています。
ただ「なぜ作らなければならないのか?」ということがわかりません。

それとも回答者様は、冒頭でおっしゃっているように、多対多の関係でDBを設計しても特に問題はないということでしょうか?

お礼日時:2008/02/03 01:27

http://gihyo.jp/dev/feature/01/database/0003

リレーショナルモデルにおいては実装がややこしくなるから。
    • good
    • 0
この回答へのお礼

早速の回答ありがとうございます。

実装がややこしくなるというのはよく聞くのですが、
なぜややこしくなるのかが知りたいです。

お礼日時:2008/02/03 01:12

このQ&Aに関連する人気のQ&A

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

関連するカテゴリからQ&Aを探す

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

Qアクセスのリレーションシップが多対多の場合について

初めて質問させていただきます。
多対多の対応方法については勉強してやっては見たのですが、うまく機能しないので質問させていただきます。

中間テーブルを作成して現在ABCの3つのテーブルがあります。頓挫しているのでかなり不備がありますが、それも踏まえて助言をお願いします。
   フィールド名は
A:aID、氏名、所有物No、数量
B:bID、aID、cID、事由、日時
C:cID、事由タイプ、タイプ1のgrade、料金、タイプ2のgrade、料金、タイプ3のgrade、タイプ3の細分タイプ、料金

Aは名簿、Bは中間用に試作、C料金体系テーブル、といった形を目指しました。
同一人物で複数請求があり、一つのフォーム上でAとBを追加、更新出来るようにしたいです。
また、料金体系のテーブルの事由タイプは3つでそれぞれgrade毎に料金体系があります。
Cのテーブルはそれぞれのタイプはその他のタイプのところは空欄になっています。

このままクエリを作って見ると追加、更新が出来ません。
以上、わかりにくいですが、助言お願いします。

Aベストアンサー

回答が付きませんね・・・・・

書かれた内容から どの様な業務で どの様にしたいのか? が解らないのです。
特に・・>C:cID、事由タイプ、タイプ1のgrade、料金、タイプ2のgrade、料金、タイプ3のgrade、タイプ3の細分タイプ、料金
のテーブルの意味が掴めません。

Exell の1行目みたいな フィールドですね。これでは クエリー操作は困るでしょうね。
テーブル構造をもう少し考え直さないと ・・・・・・

Qデータベースの1要素に複数データを格納したい

顧客管理データベースシステムを作成しようとしているのですが、
データベースの要素に複数データが入る場合の管理方法が
分からず困っています。

一例を挙げると、複数の電話番号を持つ人にも対応するように
データベース設計をしようとした場合、どのようにするのが
ベストなのかが分かりません。

電話番号1,電話番号2といったような要素を用意して、
データベースを検索するときには両方を参照する以外に
手は無いのでしょうか?

それとも顧客番号と複数電話番号検索用IDのようなものを対応させ、
電話番号データベース(電話番号ID、電話番号1、電話番号2、電話番号3)
のようなものを用意することで調べるのでしょうか?

正直、どちらもデータベース要素が3つ以上の場合に融通が利かなかったり
まだるっこしい感じがしたりするのですが、代替手段を良く知りません。
何か良い方法ございましたら、ご教示願えませんでしょうか?

Aベストアンサー

正規化して、電話番号を別テーブルに持つか、
顧客マスターに、電話1、電話2、電話3・・・と複数フィールドを持たせるか、
それぞれメリットとデメリットがあるので、
使い方次第でどちらでもいいかと思います。

固定、FAX、携帯、だけでなく、部署別とかで、多数ある可能性があるのなら、
別テーブルにした方がいいでしょう。

設計例

[顧客ID][表示順][電話番号][種別]
1111__1___012-111-1111 固定
1111__2___012-111-2222 FAX
1111__3___012-111-3333 携帯

顧客ID と 表示順 で複数フィールド主キーに設定

柔軟性が高いです。電話番号がどれだけ増えても対応できます。
joinしたものを対象に検索すれば、インデックスを使って高速に処理できます。


最大3つとか5つまでとか限定できるなら顧客マスターに全部入れてもいいでしょう。
ANo.4 で提案されている検索用のフィールドを作成するのもなかなかいいアイデアですが、デー多数が多いとインデックスが利用できないので重くなる可能性があります。
その場合は、面倒ですが、Orで連結した条件式を用意すればいいでしょう。

[電話1]=[検索番号] Or [電話2]=[検索番号] Or [電話3]=[検索番号]

正規化して、電話番号を別テーブルに持つか、
顧客マスターに、電話1、電話2、電話3・・・と複数フィールドを持たせるか、
それぞれメリットとデメリットがあるので、
使い方次第でどちらでもいいかと思います。

固定、FAX、携帯、だけでなく、部署別とかで、多数ある可能性があるのなら、
別テーブルにした方がいいでしょう。

設計例

[顧客ID][表示順][電話番号][種別]
1111__1___012-111-1111 固定
1111__2___012-111-2222 FAX
1111__3___012-111-3333 携帯

顧客ID と 表示順 で複数フィ...続きを読む

QSELECTで1件のみ取得するには?

こんにちわ。
いまORACLE9iを使用している者です。

ACCESSでは
SELECT TOP 1 項目名 FROM テーブル名
ORDER BY 項目名;
で並べ替えたデータ群のうち,先頭の1件だけを
取ることができますが,
ORACLEでそのような機能(SQL)はあるでしょうか?
教えてください。
よろしくお願いします。

Aベストアンサー

order by と rownum を併用する場合は注意が必要です。

[tbl01]
cola | colb
------------
1000 | aaaa
1001 | bbbb

というデータがある場合、
select cola from tbl01 where rownum < 1 order by cola desc;
とすると、「1001」ではなく、「1000」が返されます。
これは、order by の前に rownum < 1 が適用されてしまうからです。

解決するには、
select aaa from (select cola aaa from tbl01 order by cola desc) where rownum = 1;
とすれば良いです。

QSQLで特定の項目の重複のみを排除した全項目を取得する方法

私は仕事上でデータベースを扱っていて、タイトルのような処理を行う必要があるのですが、いかんせん方法がわからずネット上を検索しても同様だったためここで質問させていただきます。

質問点を簡単に説明いたしますと、
たとえばAというテーブルがあって、

項目名1 項目名2 項目名3 項目名4
 A    あ    ア    亜
 A    い    ア    以
 A    う    ア    宇
 B    え    イ    江
 B    お    イ    尾

上のような構造になっている場合に「項目名1」について重複している項目を排除し、結果として


項目名1 項目名2 項目名3 項目名4
 A    あ    ア    亜
 B    え    イ    江

上のようなデータを取得したいのです。
この時に、Aの重複を排除して取得するレコードは1~3行目のどれでもよいです。
また、データを取得する際には必ずそのレコードの「全項目」を取得したいのでDistinctはうまく使えませんでした。

どなたか詳しい方、方法を教えてくださると幸いです。回答お待ちしております。

私は仕事上でデータベースを扱っていて、タイトルのような処理を行う必要があるのですが、いかんせん方法がわからずネット上を検索しても同様だったためここで質問させていただきます。

質問点を簡単に説明いたしますと、
たとえばAというテーブルがあって、

項目名1 項目名2 項目名3 項目名4
 A    あ    ア    亜
 A    い    ア    以
 A    う    ア    宇
 B    え    イ    江
 B    お    イ    尾

上のよ...続きを読む

Aベストアンサー

比較可能で一意性のある値をもてる項目6をテーブルに追加して、

select T.* from T, (select Item1,min(Item6) as Item6 from T group by item1) W where T.item6=W.item6;

――ってやるのが、一番手っ取り早いと思います。
他のところに影響がでないのであればですが。
oracleならrowidを使うとか、レコードの更新時刻を突っ込むとか。

QMAX値を条件にデータを取得するには?

SQL文で困っています。
ご教授下さい。


下記のようなデータがあった場合、それぞれの区分毎に
年月が最大(最新)のデータを取得したいです。
(実際には1レコードにその他項目があり、それらも取得します。)
<検索対象データ>
区分 年月   金額
-----------------------------
A   200412  600
A   200503  560
B   200311  600
B   200508  1000
B   200504  560
C   200508  400
C   200301  1100


<取得したいデータ>

区分 年月   金額
-----------------------------
A   200503  560
B   200508  1000
C   200508  400

よろしくお願いします。

Aベストアンサー

テーブル名をXXXとすると次のようなSQLでよいと思います。(最善の方法かどうかは自信がないですが)

select B.* from (select 区分, max(年月) as 年月 from XXX group by 区分) As A
inner join XXX as B on A.区分 = B.区分 and A.年月 = B.年月
order by B.区分

Q3つの表の外部結合

表A、B、Cの3つがあり、Aのすべての行を出力したいと考えています。
外部結合を用いるのだとは思うのですが、3つの表に対して行う場合の
書き方がわからず困っています。
ご教授いただけないでしょうか?
select * from a,b,c
where a.商品ID =b.商品ID (+) and b.商品ID (+) =c.商品ID (+)
としてみましたが、うまくいきませんでした。

Aベストアンサー

ansi構文の趣旨からいえば、結合条件と絞り込み条件は分けて書くので・・

select *
from a
left join b on (a.商品ID =b.商品ID)
left join c on (b.商品ID =c.商品ID)
where a.年月 = 任意の値

と書くのが一般的でしょうね。

QCSVファイルの中で、「 , 」カンマを使いたい

「 , 」で区切られたCSVファイルの中で、「 , 」カンマを使いたいのですが、可能でしょうか?

具体的には「これは1,500円でした。」というように、CSVファイルに収められた文章内で出てくる半角の数字(お金)の区切りに使いたいのです。
全角では代用したくないのですが、CSVファイルでデータを受け渡しする際に、困っています。

例えば、特殊文字などで対応可能でしょうか?

Aベストアンサー

受け渡しに使うと言うことは相手方のアプリケーションのことも考えなければいけないのですが・・・とりあえず対応が簡単そうな方法を。

1.各セルを""で囲む。(もちろんデータにダブルクォートがある場合はカンマと同様に困ります。
2.カンマで区切らずにタブで区切る。(比較的使われない文字ですが、やはりデータ中にタブがあるとカンマと同様です)

難しいけれど完璧に対応するためには、データ中の区切り文字は特殊な文字列に変更し、受け取り側のアプリケーションではその特殊な文字列をデータ中の区切り文字として扱うという方法が使われます。
例えば、データ中のカンマは\,にするとか。

データ作成側、受け取り側でそれぞれどこまで対応できるのか分かるともっと簡単かつ具体的な方法を回答できるかも知れません。

QEXCELファイルのカレントフォルダを取得するには?

EXCELファイルのカレントフォルダを取得するには?

C:\経理\予算.xls

D:\2005年度\予算.xls

EXCEL97ファイルがあります。

VBAで
  カレントフォルダ名
(C:\経理\,D:\2005年度\)
を取得する事は可能でしょうか?

CURDIRでは上手い方法が見つかりませんでした。

Aベストアンサー

こんばんは。
Excel97 でも、同じですね。以下で試してみてください。

Sub test()
'このブックのパス
a = ThisWorkbook.Path
'アクティブブックのパス
b = ActiveWorkbook.Path
'Excelで設定されたデフォルトパス
c = Application.DefaultFilePath
'カレントディレクトリ
d = CurDir
MsgBox "このブックのパス   : " & a & Chr(13) & _
   "アクティブブックのパス: " & b & Chr(13) & _
   "デフォルトパス    : " & c & Chr(13) & _
   "カレントディレクトリ : " & d & Chr(13)
End Sub

Qアクセス:クエリの結合とリレーションシップの違いについて

アクセス初心者です。

◆ある請求システムをクエリ上の結合と関数だけでほぼ完成できました。誤作動もなく、正確な結果がでます。いわゆるリレーションシップをしないでの構築です。

◆構成は、請求対象者の個人IDをキーにして、請求対象日付、基本料、食事料、立替金、その他請求という比較的シンプルななものを結合させて作成しています。クエリ上で関数で日付のところで何月分の請求かを抽出するようなしくみです。

◆しかるに、完成させてしまってから「リレーションシップ」はしたほうがいいという内容のものをいくつかの資料でたまたま目にするようになりました。

◆しかるにクエリーでできてしまったシステムで現時点で不具合は全く発生せず、リレーションの必要性が理解できません。

◆というより、リレーションシップそのものを知らない段階でクエリの結合に取り組んだ者ですから、リレーションシップとは何ぞや?というレベルです。

◆そこで、今回、クエリの結合とリレーションシップの違いについてアドバイスをいただけないでしょうか?

よろしくお願いします。

Aベストアンサー

追記ばかりで申し訳ないです。

SQL:Structured Query Language の略。DBを操作する言語。
(詳細はネット検索などで調べてくださいね。)

クエリの実態はSQLです。
クエリをSQLビューで開いてみてください。
SELECT ・・・がそうです。
SQLで直接記述をすると、クエリのデザインビューで指定できないことも指定可能になります。
(よく利用するのか、ユニオンクエリかな?)

QデータベースのINT型項目にNULLはNG?

以前、知り合いからデータベースのINT型の項目には出来ればNULLを許可しない(NOT NULL)方がいいと聞いたことがあるのですが、本当でしょうか?

現在不動産の物件データを登録するためのシステムを作成しており、
データベースの設計を行なっている最中なのですが、
例えば金額や面積など数字しか入力されない項目はINT型にしたいと考えています。
※データベースはMySQLになります。

ただし、
物件データ登録時に数字項目に何も入力されなければ「NULL」、
0以上の数値を入力されている場合にはそのままその数値をデータベースに登録したいと考えています。
※0を入力されている場合には「0」をそのまま入れたいです。

INT型の項目にはNULLを入れるのを避けた方がいい場合には、0を入れるような仕様に変更しようと考えているのですが、その辺のことについて教えて頂けると助かります。

ざっくりとした質問で申し訳ございませんが、宜しくお願い致します。

Aベストアンサー

物件データ登録時に数字項目に何も入力されなければ「NULL」、0を入力されている場合には「0」
本来の意図としては正しいはずです。
Nullは本来、どの値を入れればいいのかわからない値ということなので、
数字がわからない=何も入力していない ということで、Nullを指定するのは正しいはずです。
しかし、
実際に使うときには、Nullは実に不自由なので、
Nullは使うなという話がでてきます。
## 私なら、入力区分 0=未入力、1=入力 と 数値(未入力は0)と別々に持つかもしれません。

というのは例えば、
金額 100万以上の物件は何件?
というSQLに対して、100件と答えがでて、
金額 100万未満の物件は何件?
というSQLに対して、50件と答えがでたとします。
じゃあ、全物件は?・・・172件だったりします。
何故?⇒Nullが22件だったためです。
(Nullは0とは違い、どちらの検索条件にも含まれません。)
・・・この不自由さを回避するために数値項目に、Not Null制約をつけることが多いです。


人気Q&Aランキング