[摘要]+---------------------+2 rows in set (0.00 sec) 多对多的关系 Ok,现在你有了一个发布在你的网站上的稳定增长的笑话数据库。事实上,这种增长是非常迅速...
+---------------------+
2 rows in set (0.00 sec)
多对多的关系
Ok,现在你有了一个发布在你的网站上的稳定增长的笑话数据库。事实上,这种增长是非常迅速的,笑话的数量会变得难以管理!你的访问者将面对一个庞大的页面,在这个页面上杂乱地排列了数以百计的笑话。现在,我们不得不考虑作一些变动了。
你决定将你的笑话放置到不同的目录中,这些目录可能是“Knock-Knock笑话”、“Crossing the Road笑话”、“Lawyer笑话”和“Political笑话”。记住我们之前的处理规则,因为我们的笑话目录是一个不同类型的“事物”,所以我们要为它们建立一个新的数据表:
mysql> CREATE TABLE Categories (
-> ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
-> Name VARCHAR(100),
-> Description TEXT
-> );
Query OK, 0 rows affected (0.00 sec)
对你的笑话定义其所属目录将会是一个困难的任务。因为一个“political”笑话可能也是一个“crossing the road”笑话,同样,一个“knock-knock”可能也是一个“lawyer”笑话。一个单个的笑话可能属于许多目录,每一个目录也会包含许多笑话。这是一个多对多的关系。
许多没有经验的设计者又会想到将几个数据存储到一个列中,最直接的解决方案是在Jokes表中增加Categories列,并在其中列举笑话所属的目录的ID。现在适用我们的第二个处理规则了:如果你需要在一个列中存储多个值,那证明你的设计可能是有缺陷的。
描述一个多对多关系的正确方法是使用一个“lookup”表。这个表不包含任何实际的数据,只是用来定义关联的事物。这儿是我们这部分的数据库设计的示意图:
JokeLookup 表将笑话的ID(JID)的目录的ID(CID)进行了关联。从上面的例子我们可以看出,以“How many lawyers...”开头的笑话既属于“Lawyer”目录,又属于“Light Bulb”目录。
建立lookup表的方法和建立其他表的方法基本一样。不同点在于选择主键。我们之前所建立的每一个表都有一个名为ID的列,这一列被我们定义为PRIMARY KEY。将一个列定义为主键意味着这一列不会出现重复值。而且可以加快基于这一列的连接操作的速度。
对于我们的lookup表来说,没有一个单个的列可以保证不出现重复值。每一个笑话可以属于几个目录,所以一个joke ID可能会出现多次;同样的,一个目录可能包含多个笑话,所以一个category ID也可能会出现多次。我们所要求的只是相同的数据对不应重复出现。因为我们这个表的唯一作用就是用来实现连接,所以使用主键来提高连接操作的速度对我们肯定有价值。所以,我们通常会为lookup表建立一个多列的主键:
mysql> CREATE TABLE JokeLookup (
-> JID INT NOT NULL,
-> CID INT NOT NULL,
-> PRIMARY KEY(JID,CID)
-> );
现在我们的表中的JID和CID共同组成了这个表的主键。保持lookup表中数据的唯一性是有价值的(防止重复定义某一个笑话属于某一个目录),而且这会提高这个表用来连接时的速度。
使用我们的lookup表中包含的目录分配,我们可以使用连接来建立几个有趣而且非常实用的查询。下面的查询列出了“Knock-Knock”目录下的所有笑话:
mysql> SELECT JokeText
-> FROM Jokes, Categories, JokeLookup
-> WHERE Name="Knock-Knock" AND
-> CID=Categories.ID AND JID=Jokes.ID;
下面这个查询列举了以“How many lawyers...”开头的笑话所属的所有目录:
mysql> SELECT Categories.Name
-> FROM Jokes, Categories, JokeLookup
-> WHERE JokeText LIKE "How many lawyers%"
-> AND CID=Categories.ID AND JID=Jokes.ID;
下面的查询,同时使用了我们的Authors表形成了一个四个表的连接(!!!),列举了写过 Knock-Knock笑话的所有作者的名字:
mysql> SELECT Authors.Name
-> FROM Jokes, Authors, Categories, JokeLookup
-> WHERE Categories.Name="Knock-Knock"
-> AND CID=Categories.ID AND JID=Jokes.ID
-> AND AID=Authors.ID;
结语
这一章中,我们学习了正确的数据库设计的基本原则,以及MySQL(实际上,对其他关系型数据库同样适用)如何对描述事件之间的不同类型的关系提供支持。我们不仅仅探讨了一对一的关系,还详细讨论了多对一、一对多以及多对多的关系。
在这一过程中,我们还学习了一些有关SQL命令的新的东西。特别的,我们学习了如何使用一个SELECT去连接多个表中的数据并将其反映到一个结果集中。
在第六章中,我们将使用我们已经获得的知识,并加上很少的一些新知识,去用PHP构建一个内容管理系统。我们希望这个系统可以提供一个可定制的、安全的、基于Web的界面来管理数据库的内容,而不再是在MySQL命令行中来解决问题。
关键词:用PHP与MySQL构建一个数据库驱动的网站(10)