0

0

用PHP和MySQL构建一个数据库驱动的网站(十)

php中文网

php中文网

发布时间:2016-06-21 09:10:43

|

1056人浏览过

|

来源于php中文网

原创

mysql|数据|数据库

  在我们目前的情况下,我们所需要的列是Jokes表中的JokeText列以及Authors表中的Name列和Email列。Jokes表和Authors表的关联条件是Jokes表中的AID列的值等于Authors表中的ID列的值。下面是一个连接的例子(前两个查询只是用来显示我们的两个表中所包含的内容):


mysql> SELECT LEFT(JokeText,20), AID FROM Jokes;
+----------------------+------+
| LEFT(JokeText,20) | AID |
+----------------------+------+
| Why did the chicken | 1 |
| A man walked into a | 1 |
| Knock knock. Who's t | 2 |
+----------------------+------+
3 rows in set (0.00 sec)

mysql> SELECT * FROM Authors;
+----+------------+---------------------+
| ID | Name | EMail |
+----+------------+---------------------+
| 1 | Kevin Yank | kyank@attglobal.net |
| 2 | Joan Smith | joan@somewhere.net |
+----+------------+---------------------+
2 rows in set (0.00 sec)

mysql> SELECT LEFT(JokeText,15), Name, Email
    -> FROM Jokes, Authors WHERE AID = Authors.ID;
+-------------------+------------+--------- -- -
| LEFT(JokeText,15) | Name | EMail
+-------------------+------------+--------- -- -
| Why did the chi | Kevin Yank | kyank@attg...
| A man walked in | Kevin Yank | kyank@attg...
| Knock knock. Wh | Joan Smith | joan@somew...
+-------------------+------------+--------- -- -
3 rows in set (0.00 sec)



  现在明白了吗?第三个SELECT的结果就是一个连接,它将存储在两个表中的数据关联数据显示到了一个结果表中,尽管我们的数据是存储在两个表中的,我们仍然可以使用一个数据库查询就获得我们的Web页面所需要的笑话列表的全部信息。

  在这里,要注意一个问题,因为在两个表中都有一个叫ID的列,所以我们在用到Authors表中的ID列时我们必须指定表名(Authors.ID)。如果我们没有指定表名,MySQL将无法知道我们指的是哪一个表中的ID,这会导致这样的一个错误:


mysql> SELECT LEFT(JokeText,20), Name, Email
    -> FROM Jokes, Authors WHERE AID = ID;
ERROR 1052: Column: 'ID' in where clause is ambiguous



  现在我们知道如何有效率地从我们的两个表中获取信息了,我们可以利用连接来重新编写我们的笑话列表的程序:


$jokelist = mysql_query(
  "SELECT JokeText, Name, EMail " .
  "FROM Jokes, Authors WHERE AID=Authors.ID");

while ($joke = mysql_fetch_array($jokelist)) {
  $joketext = $joke["JokeText"];
  $name = $joke["Name"];
  $email = $joke["EMail"];

  // Display the joke with author information
  echo( "

$joketext
" .
        "(by <A HREF='mailto:$email'>$name)

SmartB2B行业电子商务
SmartB2B行业电子商务

SmartB2B 是一款基于PHP、MySQL、Smarty的B2B行业电子商务网站管理系统,系统提供了供求模型、企业模型、产品模型、人才招聘模型、资讯模型等模块,适用于想在行业里取得领先地位的企业快速假设B2B网站,可以运行于Linux与Windows等多重服务器环境,安装方便,使用灵活。 系统使用当前流行的PHP语言开发,以MySQL为数据库,采用B/S架构,MVC模式开发。融入了模型化、模板

下载
" );
}



  随着你对数据库的使用,你会越来越发现连接的功能有多大的意义。例如,下面的查询用来显示所有由Joan Smith写的笑话:


mysql> SELECT JokeText FROM Jokes, Authors WHERE
    -> Name="Joan Smith" AND AID=Authors.ID;



  上面的查询的输出结果仅仅来源于Jokes表,但是我们使用了一个连接来通过存储在Authors表中的值搜索笑话。在我们的这篇文章中会有更多的这样的精巧的查询,在实际应用中,连接是经常会被使用的,而且在绝大多数的情况下,这会很大程度地简化我们的工作!

简单的数据关系

  对于给定的情况的最好的数据模型往往决定于我们所工作的两种数据之间的关系类型。我这篇文章中,我们将对典型的关系类型进行研究,并学会如何在一个关系型数据中用最好的方法描述它。

  对于简单的一对一的关系,只要用一个表就足够了。一对一关系的一个例子就是我们在前面已经看到的在笑话数据库中的每一个作者的e-mail地址。因为对于每一个作者只有一个e-mail地址,而且对于一个e-mail地址对应的也只有一个作者,将它们分到两个数据库中是没有道理的。

  多对一的关系可能会稍微复杂一点,但是在之前其实我们也已经解决了这个问题,我们的数据库中的每一个笑话只会有一个作者,但是同一个作者可能写了很多笑话。笑话和作者之间的关系就是一个多对一的关系。我们曾经有过一个初步的解决方案,那就是将与这个笑话关联的作者的信息也促成在同一个数据库中。但是这样做,对于同一个数据会有许多拷贝,这不仅会在同步上造成困难,而且会浪费空间。将数据分开到两个数据表中并使用一个ID列来连接两个表(象上面所说的那样使用连接),所有的问题会得到很好的解决。

  到目前为止,我们还没接触到一对多的关系,但是想象这样的一个关系应该是不困难的。在我们之前建立的数据库中,我们假定一个作者只有一个e-mail地址。事实上情况并不总是这样的,作出这个限制的理由只是因为我们只需要一个e-mail地址来与作者联系。我们简单地假设了作者总会输入他们常用的e-mail地址,或者至少是一个正常使用的e-mail地址。如果我们想要支持多个e-mail地址,我们将面对一个一对多的关系(一个作者会有几个e-mail地址,但是一个e-mail地址只会与一个确定的作者对应)。

  一个没有经验的数据库设计者面对一个一对多的关系时,他首先会想到的是试图把多个数据存储到一个数据库域中,就象这样:

  这种结构在投入使用后,要从数据库中获得一个单个的e-mail地址,将不得不通过搜索逗号(或者你所选择的用来分隔的其他符号)来分割字符串,这样做并不简单,而且会很耗时。设想一下如果要用PHP来删除某个作者的某个e-mail地址,那也将会是很困难的事。另外,对于EMail列我们需要很长的长度,这会导致磁盘空间的浪费,因为大多数的作者都只会有一个e-mail地址。

  解决一对多的关系和我们上面解决多对一的关系是非常类似的。实际上两者之前只是一个简单的颠倒。我们可将Authors表分成两个表,Authors和EMails,然后在EMails表中使用作者的ID(AID)这样的一个列来实现两个表之间的连接:

  使用一个连接,显示某个作者的所有e-mail地址将会是很简单的:


mysql> SELECT EMail FROM Authors, EMails WHERE
    -> Name="Kevin Yank" AND AID=Authors.ID;
+---------------------+
| EMail |
+---------------------+
| kevin@sitepoint.com |
| kyank@attglobal.net |
+---------------------+
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速学教程(入门到精通)
PHP速学教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
Python 序列化
Python 序列化

本专题整合了python序列化、反序列化相关内容,阅读专题下面的文章了解更多详细内容。

12

2026.02.02

AO3官网入口与中文阅读设置 AO3网页版使用与访问
AO3官网入口与中文阅读设置 AO3网页版使用与访问

本专题围绕 Archive of Our Own(AO3)官网入口展开,系统整理 AO3 最新可用官网地址、网页版访问方式、正确打开链接的方法,并详细讲解 AO3 中文界面设置、阅读语言切换及基础使用流程,帮助用户稳定访问 AO3 官网,高效完成中文阅读与作品浏览。

200

2026.02.02

主流快递单号查询入口 实时物流进度一站式追踪专题
主流快递单号查询入口 实时物流进度一站式追踪专题

本专题聚合极兔快递、京东快递、中通快递、圆通快递、韵达快递等主流物流平台的单号查询与运单追踪内容,重点解决单号查询、手机号查物流、官网入口直达、包裹进度实时追踪等高频问题,帮助用户快速获取最新物流状态,提升查件效率与使用体验。

98

2026.02.02

Golang WebAssembly(WASM)开发入门
Golang WebAssembly(WASM)开发入门

本专题系统讲解 Golang 在 WebAssembly(WASM)开发中的实践方法,涵盖 WASM 基础原理、Go 编译到 WASM 的流程、与 JavaScript 的交互方式、性能与体积优化,以及典型应用场景(如前端计算、跨平台模块)。帮助开发者掌握 Go 在新一代 Web 技术栈中的应用能力。

15

2026.02.02

PHP Swoole 高性能服务开发
PHP Swoole 高性能服务开发

本专题聚焦 PHP Swoole 扩展在高性能服务端开发中的应用,系统讲解协程模型、异步IO、TCP/HTTP/WebSocket服务器、进程与任务管理、常驻内存架构设计。通过实战案例,帮助开发者掌握 使用 PHP 构建高并发、低延迟服务端应用的工程化能力。

16

2026.02.02

Java JNI 与本地代码交互实战
Java JNI 与本地代码交互实战

本专题系统讲解 Java 通过 JNI 调用 C/C++ 本地代码的核心机制,涵盖 JNI 基本原理、数据类型映射、内存管理、异常处理、性能优化策略以及典型应用场景(如高性能计算、底层库封装)。通过实战示例,帮助开发者掌握 Java 与本地代码混合开发的完整流程。

9

2026.02.02

go语言 注释编码
go语言 注释编码

本专题整合了go语言注释、注释规范等等内容,阅读专题下面的文章了解更多详细内容。

62

2026.01.31

go语言 math包
go语言 math包

本专题整合了go语言math包相关内容,阅读专题下面的文章了解更多详细内容。

56

2026.01.31

go语言输入函数
go语言输入函数

本专题整合了go语言输入相关教程内容,阅读专题下面的文章了解更多详细内容。

28

2026.01.31

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Excel 教程
Excel 教程

共162课时 | 15.2万人学习

Pandas 教程
Pandas 教程

共15课时 | 1万人学习

C# 教程
C# 教程

共94课时 | 8.4万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号