web-dev-qa-db-ja.com

PHP)で外部キーを使用する方法

したがって、外部キーの作成方法を理解し、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を使用する方法の例をいくつか示していただければ幸いです。完全な説明が必要です。

また、正規化と非正規化という用語を理解する必要があります。これらの用語を例を挙げて詳細に説明するリンクをいくつか提供していただければ幸いです。また、データベースの設計や実装などの初心者向けの優れた本について何か提案があれば、本当にありがたいです。

どうもありがとう。

7

外部キー列/制約の明確化

したがって、外部キーの作成方法を理解し、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行の異なるparentsを参照していることに注意してください。は彼自身の親であり、誰の父親も彼の母親ではありません。

20
geomagas

結合には外部キーが使用されます。たとえば、特定のアイテムを購入したユーザー名を知りたい場合は、次のように記述します。

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列を複製する必要があります。 nameitemの単なる属性であり、特定の購入に固有のものではありません。購入したアイテムの名前を取得する必要がある場合は、itemsテーブルに参加してください。

4
Barmar

非常に多くのリンクを読む代わりに、単純なプロジェクトにこれを実装してみてください。上記のテーブルの使用方法を説明しているだけです。

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
1
Shafeeque

同じ方法で、外部キーがないかのように、PHPで外部キーを使用してテーブルをツリー化します。外部キーはデータベースで定義されており、(ほとんど)phpとは何の関係もありません。 PHPで実行する必要があるのは、SQLクエリによって返される可能性のある潜在的なエラーに対応することだけです。これにより、外部キーの制約が解消されます(通常はDELETEクエリ)。

また、データベーススキーマの場合は、「テーブルuser_purchase」から列「name」を削除する必要があります。冗長です。

0
Jardo

正規化/非正規化のポイントを見るだけです。

正規化は、データベースの冗長性を削除しようとするプロセスです。この例では、user_purchasenameフィールドは冗長です-i_idを使用してitemsテーブルでアイテムを検索すると、アイテムの名前を見つけることができます。

したがって、user_purchaseの正規化を検討する場合は、おそらくnameフィールドを削除し、JOINを使用して、必要なときにそれを取得します。もちろん、これは、itemsへの2番目のFOREIGN KEY参照が必要ないことも意味します。

非正規化は基本的に逆の方法で行われ、冗長性が追加されます。通常はパフォーマンス上の理由から行われます。

ただし、あなたの例では、ビジネス上の理由から非正規化を検討することもできます。たとえば、請求書を再印刷できるようにする必要がある場合に備えて、ユーザーが実際に購入したときの製品名を(現在の名前ではなく)保存することが重要であると判断する場合があります。ただし、この場合でも、FOREIGN KEYitemsに戻すことは望ましくありません(製品の名前が変更されると「壊れて」しまうため)。

0
Clart Tent