したがって、外部キーの作成方法を理解し、FKの目的が何であるかを理解しています。しかし、私はそれらの使い方を理解するのに問題があります。外部キーについて質問しました こちら(リンクをクリック)
これが私が作ったものです:
CREATE TABLE user(
id INT(11) NOT NULL AUTO_INCREMENT,
username VARCHAR(50) NOT NULL,
password VARCHAR(20) NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE items(
i_id INT(11) NOT NULL AUTO_INCREMENT,
name TINYTEXT NOT NULL,
price DECIMAL(8,2) NOT NULL,
PRIMARY KEY (i_id)
);
CREATE TABLE user_purchase(
i_id INT(11) NOT NULL,
name TINYTEXT NOT NULL,
id INT(11) NOT NULL,
FOREIGN KEY (i_id) REFERENCES items(i_id),
FOREIGN KEY (name) REFERENCES items(name),
FOREIGN KEY (id) REFERENCES user(id)
);
今私の質問は、PHPを使用してこれをどのように最大限に活用するかです。上記のリンクから、user_purchaseテーブルで外部キーを1つだけ使用するのが良いと言われていますが、複数の列が必要な場合はどうなりますか?同じテーブルの異なる列に複数の外部キーを使用しないのはなぜですか?
私はmysqlとphpを使用しています。 MYSQLコマンドを使用して情報を取得するために外部キーを持つテーブルでPHPを使用する方法の例をいくつか示していただければ幸いです。完全な説明が必要です。
また、正規化と非正規化という用語を理解する必要があります。これらの用語を例を挙げて詳細に説明するリンクをいくつか提供していただければ幸いです。また、データベースの設計や実装などの初心者向けの優れた本について何か提案があれば、本当にありがたいです。
どうもありがとう。
したがって、外部キーの作成方法を理解し、FKの目的が何であるかを理解しています。しかし、私はそれらの使い方を理解するのに問題があります。
外部キー制約を参照していると仮定すると、簡単な答えはそれらを使用しないになります。
そして、ここに長いものがあります:
列は外部キーを他のテーブルに参照することに慣れています。特に正規化プロセスでは、"_user_purchase.i_id
_はitems
テーブルへの外部キーです"のようなフレーズが非常に一般的です。これは関係を説明するための完全に有効な方法ですが、実装フェーズに達すると少しあいまいになる可能性があります。
テーブルを作成したとしますなし _FOREIGN KEY
_句:
_CREATE TABLE user(
id INT(11) NOT NULL AUTO_INCREMENT,
username VARCHAR(50) NOT NULL,
password VARCHAR(20) NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE items(
i_id INT(11) NOT NULL AUTO_INCREMENT,
name TINYTEXT NOT NULL,
price DECIMAL(8,2) NOT NULL,
PRIMARY KEY (i_id)
);
CREATE TABLE user_purchase(
i_id INT(11) NOT NULL,
name TINYTEXT NOT NULL,
id INT(11) NOT NULL,
);
_
関係的には、外部キーcolumnsはまだ実装されているであることに注意してください。 user
テーブル(id
)を参照する列とitems
テーブル(_i_id
_)を参照する列があります-name
列を少し脇に置きます。次のデータを検討してください。
_ user user_purchase items
| id username | | id i_id | | i_id name price |
| 23 john | | 55 10 | | 10 chocolate bar 3.42 |
| 55 mary | | 70 10 | | 33 mobile phone 82.11 |
| 70 fred | | 70 33 | | 54 toothpaste 8.67 |
| 55 10 | | 26 toy car 6.00 |
| 70 26 |
_
関係はそこにあります。これは、誰が何を購入したかに関する情報を保持する_user_purchase
_テーブルを使用して実装されます。関連するレポートをデータベースに照会する場合は、次のようにします。
_select * from user_purchase p
join user u on (p.id=u.id)
join items i on (p.i_id=i.i_id)
_
そして、それがリレーションと外部キーの使用方法ですcolumns関与します。
さて、もし私たちがそうしたらどうなるでしょう:
_insert into user_purchase (id,i_id) values (23,99)
_
どうやら、これは無効なエントリです。 _id=23
_のユーザーはいますが、_i_id=99
_のアイテムはありません。 これ以上のことはわかりませんであるため、RDBMSはそれを可能にします。それでも。
そこで外部キー制約が作用します。 _user_purchase
_テーブル定義でFOREIGN KEY (i_id) REFERENCES items(i_id)
を指定することにより、基本的にRDBMSに従うルールを与えます。_i_id
_に含まれていない_items.i_id
_値を持つエントリ)__列は受け入れられません。言い換えると、外部キー列は参照を実装しますが、外部キー制約は参照整合性を強制します。
ただし、FK制約を定義したからといって、上記のselect
は変更されないことに注意してください。したがって、yoデータを保護するために、RDBMSが使用するFK制約を使用しないでください。
...複数の列が必要な場合はどうなりますか?同じテーブルの異なる列に複数の外部キーを使用しないのはなぜですか?
自問してみてください:なぜあなたはそれが欲しいのですか? 2つの外部キーが同じ目的を果たす場合、冗長性は最終的に問題を引き起こします。次のデータを検討してください。
_ user_purchase items
| id i_id name | | i_id name price |
| 55 10 chocolate bar | | 10 chocolate bar 3.42 |
| 70 10 chocolate bar | | 33 mobile phone 82.11 |
| 70 33 mobile phone | | 54 toothpaste 8.67 |
| 55 10 toothpaste | | 26 toy car 6.00 |
| 70 26 toy car |
_
この写真の何が問題になっていますか?ユーザーは_55
_チョコレートバーを2つ購入しましたか、それともチョコレートバーと歯磨き粉を購入しましたか?この種のあいまいさは、データの同期を維持するために多くの労力をもたらす可能性があります。これは、外部キーの1つだけを保持する場合は不要です。実際、関係によって暗示されているので、name
列を完全に削除しないのはなぜですか。
もちろん、複合外部キーを実装するか、items
テーブルにPRIMARY KEY(i_id,name)
を設定する(または追加のUNIQUE(i_id,name)
インデックスを定義する)ことで、これを解決できます。本当に重要です)そしてFOREIGN KEY(i_id,name) REFERENCES items(i_id,name)
を設定します。このように、items
テーブルに存在する(i_id、name)カップルのみが_user_purchases
_に対して有効になります。 まだone外部キーであるという事実は別として、_i_id
_列がアイテムを識別するのにすでに十分である場合、このアプローチは完全に不要です( name
列について同じことを言うことはできません...)。
ただし、テーブルに複数の外部キーを使用することに対する規則はありません。実際、そのようなアプローチを必要とする状況があります。 person(id,name)
テーブルとparent(person,father,mother)
テーブルについて、次のデータを使用して考えてみます。
_ person parent
| id name | | person father mother |
| 14 John | | 21 14 59 |
| 43 Jane | | 14 76 43 |
| 21 Mike |
| 76 Frank |
| 59 Mary |
_
明らかに、parent
テーブルの3つの列はすべてperson
への外部キーです。 同じ関係ではありません、ただしつの異なる関係:人の親も人であるため、対応する2つの列は同じテーブルを参照する必要がありますperson
します。ただし、3つのフィールドはcanだけでなく、have to同じperson
行の異なるparent
sを参照していることに注意してください。は彼自身の親であり、誰の父親も彼の母親ではありません。
結合には外部キーが使用されます。たとえば、特定のアイテムを購入したユーザー名を知りたい場合は、次のように記述します。
select u.username
from items i
join user_purchase up on i.i_id = up.i_id
join user u on u.id = up.id
where i.name = "Some product name"
また、データベースエンジン自体によって使用される場合もあります。 id
またはuser_purchase
列が他のテーブルの参照列のいずれとも一致しない行をi_id
に作成したかどうかを検出できます。
notuser_purchase
テーブルのname
列を複製する必要があります。 name
はitem
の単なる属性であり、特定の購入に固有のものではありません。購入したアイテムの名前を取得する必要がある場合は、items
テーブルに参加してください。
非常に多くのリンクを読む代わりに、単純なプロジェクトにこれを実装してみてください。上記のテーブルの使用方法を説明しているだけです。
user
テーブルに3人のユーザーがいて、items
テーブルに5人のアイテムがあるとします。
user
テーブル
id | username | password
1 abc 123
2 def 456
3 qwe 987
items
テーブル
i_id | name | price
1 item 1 6
2 item 2 8
3 item 3 11
4 item 4 3
5 item 5 14
きみの user_purchase
テーブルは次のようになります
CREATE TABLE user_purchase(i_id INT(11)NOT NULL、id INT(11)NOT NULL、FOREIGN KEY(i_id)REFERENCES items(i_id)、FOREIGN KEY(id)REFERENCES user(id));
この表では、アイテム名は再度必要ありません。だから私は削除しました。
i_id | id
1 1
1 2
2 2
3 3
上記の表では、ユーザー1がアイテム1を購入し、ユーザー2がアイテム1、アイテム2を購入し、ユーザー3がアイテム3を購入しています。
これが正規化の仕組みです。 MySQL JOINを使用して、ユーザー名とアイテムの詳細を取得できます
SELECT B.user_name,C.name AS item_name,C.price
FROM user_purchase A
JOIN user B ON A.id = B.id
JOIN items C ON A.i_id = C.i_id
参加するための外部キーの使用は次のとおりです
A.id = B.id
A.i_id = C.i_id
同じ方法で、外部キーがないかのように、PHPで外部キーを使用してテーブルをツリー化します。外部キーはデータベースで定義されており、(ほとんど)phpとは何の関係もありません。 PHPで実行する必要があるのは、SQLクエリによって返される可能性のある潜在的なエラーに対応することだけです。これにより、外部キーの制約が解消されます(通常はDELETEクエリ)。
また、データベーススキーマの場合は、「テーブルuser_purchase」から列「name」を削除する必要があります。冗長です。
正規化/非正規化のポイントを見るだけです。
正規化は、データベースの冗長性を削除しようとするプロセスです。この例では、user_purchase
のname
フィールドは冗長です-i_id
を使用してitems
テーブルでアイテムを検索すると、アイテムの名前を見つけることができます。
したがって、user_purchase
の正規化を検討する場合は、おそらくname
フィールドを削除し、JOIN
を使用して、必要なときにそれを取得します。もちろん、これは、items
への2番目のFOREIGN KEY
参照が必要ないことも意味します。
非正規化は基本的に逆の方法で行われ、冗長性が追加されます。通常はパフォーマンス上の理由から行われます。
ただし、あなたの例では、ビジネス上の理由から非正規化を検討することもできます。たとえば、請求書を再印刷できるようにする必要がある場合に備えて、ユーザーが実際に購入したときの製品名を(現在の名前ではなく)保存することが重要であると判断する場合があります。ただし、この場合でも、FOREIGN KEY
をitems
に戻すことは望ましくありません(製品の名前が変更されると「壊れて」しまうため)。