所以我理解如何创建外键,我知道FK的目的是什么。但是我在理解如何使用它们时遇到了问题。我问了一个关于外键的问题HERE(Click link)
这是我做的:
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表中只使用一个外键是好的,但如果我想要多个列呢?为什么我们不为同一个表的不同列使用多个外键?
我正在使用mysql和php。如果你能展示一些如何使用带有外键的表来使用PHP来获取使用MYSQL命令获取信息的例子,我将不胜感激。我真的需要一个彻底的解释。
我还需要理解术语规范化和非规范化。如果您能够通过示例详细解释这些术语,或者如果您对数据库设计,实现等初学者的一些好书有任何建议,我将不胜感激,我将非常感激。
非常感谢。
答案 0 :(得分:21)
所以我理解如何创建外键,我知道是什么 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,
);
请注意,在关系方面,外键列仍然是 。有一列引用了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)
这就是我们如何使用关系和所涉及的外键列。
现在,如果我们这样做:
insert into user_purchase (id,i_id) values (23,99)
显然,这是一个无效的条目。虽然有id=23
的用户,但没有i_id=99
的项目。 RDBMS允许这种情况发生,因为它不知道更好的。然而。
这就是外键约束发挥作用的地方。通过在FOREIGN KEY (i_id) REFERENCES items(i_id)
表定义中指定user_purchase
,我们基本上为RDBMS提供了以下规则: i_id
列中未包含items.i_id
值的条目是不可接受的。换句话说,当外键列实现引用时,外键约束强制执行引用完整性 强>
但请注意,上述select
不会改变,只是因为您定义了FK约束。因此,你不使用FK约束,RDBMS会这样做,以保护您的数据。
......如果我想要几列怎么办?为什么我们不使用几个外国人 同一个表的不同列的键?
问问自己:你为什么要这样?如果两个外键用于同一目的,冗余最终会让您遇到麻烦。请考虑以下数据:
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
买了两个巧克力棒,巧克力棒和牙膏吗?这种模糊性会导致为保持数据同步而付出很多努力,如果我们只保留一个外键,这将是不必要的。事实上,为什么不完全删除name
列,因为关系暗示了它。
当然,我们可以通过实现复合外键来解决这个问题,方法是为PRIMARY KEY(i_id,name)
表设置items
(或定义额外的UNIQUE(i_id,name)
索引,这一点并不重要)然后设置FOREIGN KEY(i_id,name) REFERENCES items(i_id,name)
。这样,items
表中仅存在的(i_id,name)伴随对user_purchases
有效。除了你还有一个外键之外,如果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
表的所有三列都是person
的外键。 不是为了相同的关系,但是对于三个不同的:由于一个人的父母也是人,因此两个相应的列必须引用同一个表person
确实。但请注意,三个字段不仅可以而且必须在同一person
行中引用不同的parent
,因为没有人他自己的父母和没有人的父亲也是他的母亲。
答案 1 :(得分:4)
外键用于连接。例如,如果您想知道购买特定商品的用户名,请写下:
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"
它们也可能被数据库引擎本身使用。它可以检测您是否在user_purchase
中创建了一行,其中id
或i_id
列与另一个表中引用列中的任何内容都不匹配。
您应该不复制name
表格中的user_purchase
列。 name
只是item
的一个属性,并不特定于任何特定购买。如果您需要获取已购买商品的名称,请使用items
表格加入。
答案 2 :(得分:1)
不要阅读这么多链接,只是尝试在任何简单的项目中实现它。我只是在解释我们将如何使用上表。
假设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项目(i_id), FOREIGN KEY(id)REFERENCES用户(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
答案 3 :(得分:0)
你在php中使用外键密集表格,就好像它们没有外键一样。外键在数据库中定义,并且(几乎)与php无关。你在php中唯一需要做的就是对sql查询可能返回的潜在错误做出反应,这会产生外键约束(通常是DELETE查询)。
对于您的数据库架构,您应该从“table user_purchase”中删除列“name”。这是多余的。
答案 4 :(得分:0)
只需查看规范化/反规范化点:
规范化是尝试删除数据库中的冗余的过程 - 在您的示例中name
中的user_purchase
字段是多余的 - 我可以通过查找项目的名称来查找项目的名称使用items
的{{1}}表。
因此,如果我们要查看规范化i_id
,我们可能会移除user_purchase
字段,并在需要时使用name
来检索它。当然,这也意味着我们不需要对JOIN
的第二个FOREIGN KEY
引用。
反规范化基本上是相反的 - 添加冗余 - 通常是出于性能原因而做的。
但是,在您的示例中,您也可能出于业务原因考虑取消规范化。例如,您可能认为将产品名称存储为用户实际购买时的名称(而不是现在所称的产品名称)非常重要 - 以防万一您需要能够重新打印发票。但是,即使在这种情况下,您也不希望items
返回FOREIGN KEY
(因为如果重新命名产品,它会“中断”)。