MySQL入门

本章主要介绍MySQL关系数据库管理系统(Relational Database Management System,RDBMS)和MySQL所使用的结构化查询语言(Structured Query Language,SQL)。其中,列出了应该掌握的基本术语和概念,描述了示例所要用到的样本数据库sampdb,并且提供了一个用于展示如何使用`MySQL创建数据库并与之进行交互操作的教程。

如果你对数据库系统还不甚了解,或者还不是很肯定自己是否需要学习它,甚至还不肯定是否需要使用它,那么请从本章开始。如果你对MySQL和SQL还一无所知,并且需要一个入门指南,那么也请从本章开始。对MySQL或其他数据库系统已有一定经验的读者,则可以略读一下本章的内容。不过,为了你能对全书所用那个数据库sampdb的目的和内容更熟悉,希望可以阅读一下1.2节。

1.1 MySQL的用途

本节描述的是MySQL数据库系统的用途,具体描述了“MySQL可以干什么”,以及“它如何才能给你提供帮助”。如果你已经明白数据库的用途(也许你正在思考某个问题,到这里来只是想要找出“如何使用MySQL来解决它”的答案),那么可以直接翻阅到1.2节。

数据库系统在本质上是一种高效的管理大量列表信息的办法。这些信息的来源可能多种多样。它可能是研究数据、业务记录、客户需求、体育统计、销售报告、个人信息、人事档案、bug报告或者学生成绩。发挥数据库系统强大作用的时机在于:想要组织和管理的信息非常庞大或复杂,以至于所有记录采用手工处理会变得异常繁重。对于每天处理上百万条事务的大公司来说,数据库是必不可少的。不过,即使只有一个人的小公司,也可能会维护很多的信息,甚至多到需要用一个数据库来管理它。假设有下面这些情况。

  • 你在牙科诊所工作,在那里需要管理好患者的跟踪记录:何人何时到访、做了些什么、下次预约信息、保险信息等。
  • 你收集了多年的研究数据,为了发表而需要对它们进行分析。你要从大量原始数据里提炼出摘要性的信息,并取出选中的观察子集进行详细的统计分析。
  • 你是一名教师,需要跟踪学生的成绩和考勤。每次考试结束,你都需要记录每一个学生的分数。虽然将成绩记录到成绩册上很简单,但之后的成绩分析却很繁琐。你很想避免为了确定分数曲线,而对每次考试的分数进行排序;也真的很不愿意在期末时为了确定最终成绩,而把每个学生的成绩都加起来。统计每个学生的考勤也很无趣。
  • 你在某个组织机构(可能是一个专业团体、一个俱乐部、一个交响乐团或者一个健身俱乐部)担任秘书一职,具体负责维护机构成员名录的工作。你每年都要为所有成员生成一份打印名录,名录是用文字处理软件管理的,每当成员资料有变化时你都得编辑更新。你非常厌倦这种维护名录的方式,因为它限制了你的发挥,主要表现在:很难对名录条目按不同方式进行排序;无法轻松地选到每一条目的指定部分,如列出人名和电话号码;更不能轻松地找出一组的成员,如需要尽快更新成员资格的成员。如果有办法,就可以省却每月通过翻阅这些条目来找出那些需要更新成员资格的成员的工作。你听说过“无纸化办公”,知道它是电子化记录发展的结果,但你还未见过它所带来的任何好处。虽然成员资格记录是电子化的,但具有讽刺意味的是,它们记录的形式除了能将名录打印成纸质的以外,很难用作他途!

上面这些场景所涉及的信息量有大有小。但它们都有一个共同的特点,即这些工作都可以通过手工来完成,但使用数据库系统来管理会更高效。

在使用像MySQL这样的数据库系统时,你希望从中获得哪些具体好处呢?这取决于你的特殊需要和需求,并且,如同上面示例所示,具体的好处都各不相同。不过,在一般情况下,适合于用数据库管理系统来处理任务的人群是那些不使用数据库管理系统就要使用文件柜的人。事实上,数据库系统就像一个内置了复杂文件系统的巨大文件柜。与手工管理记录的方式相比,以电子化方式来管理记录存在有许多优势。下面来看看前面描述过的那个牙科诊所的场景。在用于管理患者记录的文档系统能力方面,MySQL可以为你带来下面这些帮助。

(1)缩短记录归档时间。你不用在文件柜里挨个拉抽屉找存放新记录的地方。你只需将它提交给MySQL,MySQL会为你找到正确的存放这条记录地方。

(2)缩短记录检索时间。当进行记录查找时,不必为了想要找到的记录而亲自动手去逐个搜索。为了给那些最近一段时间没来做检查的患者发个提醒信息,你可以让MySQL来帮你找出这些记录。当然,这与让你告诉另一个人“请帮忙确认一下最近6个月哪些患者没来参加检查”的情况有所不同。事实上,你“念出的”是一段奇怪的“咒语”:

SELECT last_name, first_name, last_visit FROM patient  
WHERE last_visit < DATE_SUB(CURDATE(), INTERVAL 6 MONTH);

如果你以前从没见过类似的内容,那么它初看起来可能会相当吓人。不过,它的效果却是相当吸引人:你不用再花费一小时来翻看你的记录,只需一两秒即可得到想要的结果。不管怎样,无需多久你就会习惯这种奇形怪状的表达。等阅读完本章,你便会明白它真正的含义。

(3)灵活的检索排序。不用严格按照记录存储的顺序(如按患者的名字排序)来检索它们。MySQL可以按任何你想要的顺序来提取记录,如按名字、保险公司名字、上次就诊时间等。

(4)灵活的输出格式。在找到感兴趣的记录之后,你无需手动复制这些信息,MySQL会为你生成一个列表。有时,你可能只是想打印这些信息;有时,你可能会想在另一个程序里使用它们。例如,在生成了最近逾期未能复诊的患者名单后,你便可以把这些资料输送到某个文字处理软件,让它打印出你想要发送给那些患者的通知单。或许,你只是对如同“选中记录统计”这样的汇总信息比较感兴趣。你不用亲自来统计记录,MySQL会替你生成汇总信息。

(5)多用户同时访问记录。对于纸质记录,如果有两个人同时想要查看某个记录,那么其中一个人就必须等待另一个人将这个记录归还之后才能查看。而MySQL则可以允许这两个人同时访问这个记录。

(6)记录的远程访问与电子传输。想用纸质记录,就得亲自跑到存放它们的地方,或者让人将它们复印之后再发送给你。电子记录则为远程访问记录或者电子传输记录提供了可能。如果你的牙科集团设有许多分支机构,那么这些机构里的人员便可以在当地访问到你的资料。你完全不用再通过快递来传送这些副本。如果有人需要记录,但却又没有与你一样的数据库软件,那么你可以选择那些所需的记录,将其中的内容通过网络发送给他。

如果你曾经用过数据库管理系统,那么肯定对刚才描述的种种好处深有体会,而且可能也在思索如何才能超越常规“代替文件柜”应用程序的限制。有许多组织机构将数据库与网站结合在一起使用,这就是一种很好的方式。假设贵公司有一个商品库存数据库,每当顾客打电话过来询问仓库里是否有货、其价格是多少时,服务台的员工便会用到它。这是一种比较传统的数据库使用方式。不过,如果贵公司搭建一个供顾客访问的网站,那么就可以提供一项新的服务:创建一个搜索页面,让顾客可以查看条目,从而确定价格、可用性以及商品的库存情况。如果支持在线订购,那么顾客甚至不用离开家门便能购买到你的产品。这让顾客获得了他们想要的信息,而数据库却是根据提问自动搜索商品库存信息来提供这些内容的。顾客立即获得了所关心的信息,不用一边听着恼人的录音,一边傻等着;也不用受限于服务台的上下班时间。并且,每当有一位顾客使用贵公司网站,就意味着会少一个电话,而这是需要由一个在服务台拿工资的人来处理的事情。如此看来,该网站或许可以为自己买单。

不过,你还可以更进一步地发挥数据库的作用。基于Web的库存搜索请求,不仅可以把信息提供给顾客,也能提供给贵公司。这些查询可以让你了解到顾客正在查找哪些商品,而查询结果则会让你知道是否能够满足他们的需求。在某种程度上,如果你没有顾客想要的东西,那么你可能会错失这笔生意。因此,记录下库存搜索信息非常有意义,通过它可以了解到:顾客正在找寻什么商品,而你是否还有存货。接着,就可以根据这些信息来调整库存,并向顾客提供更好的服务。

说了半天,那么MySQL是如何工作的呢?找到答案的最好方式就是自己动手体验一下。为此,我们需要有一个可以操作的数据库。


1.2 示例数据库

本节将描述本书所使用的示例数据库。在你学习使用MySQL的过程中,可以用这个数据库提供的示例进行尝试,该数据库是针对之前描述过的两种情况设计的。

  • “机构秘书”场景。该机构有一些特点:其成员对美国历史很感兴趣(因没有一个更好的名字,所以姑且称其为“美史联盟”)。所有成员都要定期缴纳一定的费用以维持其成员资格。缴纳的费用会用于一些正常开支,如出版通讯——《Chronicles of U.S. Past 》(美国编年史)。该联盟运营着一个小型网站,但还未被充分开发出来,而你很想要扭转这一局面。
  • “成绩考评”场景。你是一名教师,要负责考评期间的各种考试与测验,记录分数和打分。之后,你要确定出最终成绩,并把它们随同考勤情况一同上交到学校办公室。

下面,我们进一步分析一下这两个场景的需求。

  • 你必须决定数据库里的哪些内容是你所想要的——即那些你要实现的目标。
  • 你必须决定需要将哪些内容放入数据库——即你想要跟踪的数据是什么。

在考虑“将什么放入数据库”之前考虑“要从数据库里获得什么样的内容”,这似乎有些本末倒置。毕竟,大家都是这么认为的:要先输入数据,然后才能检索它。不过,你使用数据库的方式取决于你的目标是什么。而且,与想要放入数据库的内容相比,想要从数据库检索的内容则与那些目标的关系更加密切。只有在计划今后使用这些信息之后,你才会想要花费时间和精力把它们放入数据库。

1.2.1 美史联盟项目

该项目的场景是:你是联盟秘书,眼下正使用某个文字处理文档维护那份成员资格名单。对于像“生成打印名录”这样的事情,处理起来当然没什么问题。但是,当你想要获得其他更多信息时,就会受到限制。你还有几个目标要实现。

  • 你想要以不同格式输出名录,同时按照不同的应用程序来定制信息。有一个目标是每年生成打印好的名录——这是联盟一直以来的一个需求,要继续实施下去。你可能还会想到名录信息的其他用途,例如向出席联盟年会的人员提供一份打印好的最新成员名单。这两个应用程序涉及的信息是不同的。打印名录程序需要用到每个成员条目的所有内容。而年会程序则只需要提取出成员的姓名即可(使用文字处理软件无法轻松完成这项工作)。
  • 你想要在名录里搜索出满足不同条件成员。例如,你想要知道近期有哪些成员需要更新成员资格。你还需要另一个搜索相关的应用程序,用来维护每个成员各自的关键字列表。这些关键字描述了所有成员都特别感兴趣的一些美国历史时期,如南北战争(Civil War)、经济大萧条(Depression)、民权法案(civil right)、托马斯·杰斐逊(Thomas Jefferson)总统的生平事迹。有时,有些成员会要求你为他们提供一份与其志趣相投的其他成员名单,而你也很愿意满足这些需求。
  • 你想要将名录发布到联盟网站上去。这样做能让你和所有成员都受益。如果你能通过某些自动化的过程将名录转换为Web页面,那么名录的在线版本将总能保持最新,而这是纸质形式无法做到的。如果在线名录能支持搜索功能,那么成员们便能轻松地自行查找信息。例如,如果某成员想要知道其他还有谁对“南北战争”感兴趣,那么他便可以自行查找,完全用不着等你帮他搜索,而你也不用抽时间去处理这件事情。

数据库不是世界上最令人兴奋的工具,因此我不会鼓吹像“使用数据库能激发人的创造性思维”这样不切实际的话。不过,如果你不再把信息看成是一种累赘(如同你在使用文字处理文档时所想的那样),而是把它想成是可相对轻松处理的事情(如同你希望使用MySQL来处理一样),那么你自然会释放出自己的潜能,找到更多新的使用这些信息的方法。

  • 如果数据库中的信息能够以在线名录的形式放到网站上去,那么你也可以让这些信息以其他方式流转。例如,让成员能够在线修改他们自己的资料,并更新到数据库。这样,你就不用自己负责所有的编辑工作,而且这也能让名录里的信息更加准确。
  • 如果你把电子邮件地址也存储到数据库里,那么你就可以利用它们来给成员发送电子邮件,提醒他们及时更新自己的资料。邮件内容可以显示出成员的当前资料,请成员们进行检查,并提示他们如何使用网站提供的功能完成必要的修改。
  • 数据库还可以在很多方面拓展联盟网站的用途,而并不仅限于成员资格列表。联盟通讯《Chronicles of U.S. Past》有一个儿童专栏,其中每一期都会包含一个历史知识测验。最近几期的重点是美国总统的传记。联盟网站上也可以设置一个儿童专区,把那些测验题目放在上面。或许这个专区还可以弄成互动的,比如将做过的测验信息放入数据库,让Web服务器在数据库里查询问题的答案,然后呈现给访客。

好了!此时此刻,你所想到的数据库应用数量可能让你有些忘乎所以了。在稍息片刻之后,重新回到现实,你开始问一些比较实际的问题,例如:

  • 是不是想太多了?实现起来工作量会很大吧?

当然,所有事情只想不做都会变得很容易,而这些想法对于具体实现根本不重要。不过,在读完本书之后,你就能实现我们刚才罗列出来的所有需求。但是请记住,没有必要一下子完成所有需求。要将整个工作分解成若干需求,一次只解决一个需求。

  • MySQL能实现所有这些目标吗?

不,它不能,至少单靠它是不行。例如,MySQL没有内置Web程序开发工具。不过,你可以将它与其他工具相结合,借助它们来补充和扩展其功能。

我们将使用脚本语言Perl和它的数据库接口(Database Interface,DBI)模块来编写访问MySQL数据库的脚本程序。Perl语言有着强大的文本处理能力,它能以极其灵活的方式对数据库的查询结果进行处理,并产生各式各样的输出。例如,我们可以用Perl语言生成一份富文本格式(Rich Text Format,RTF)格式的成员名录,该格式可供各种文字处理软件读取;另外,还可以生成适用于Web浏览器的HTML格式的名录。

我们还要用到另一种脚本语言PHP。PHP语言特别适用于编写Web应用程序,并且它也易与数据库进行交互。有了它,你就能够通过Web页面来启动MySQL查询,然后生成新的包含数据库查询结果的页面。有很多支持PHP语言的Web服务器(其中包括世界上最流行的Web服务器Apache),因此像“呈现一个搜索表单,并显示搜索结果”这样的事情,对它来说就是“小菜一碟”。

MySQL与这些工具可以很好地集成在一起,因此你可以自由地选择组合方式,以便达到你心中设定的目标。别太相信那些一体化的套装组件,它们通常都大肆鼓吹自己具有“集成”功能,但是它们只有彼此配合才能更好地发挥作用。

  • 最后,还有一个很重要的问题:总计要花费多少钱?毕竟联盟的预算是有限的。

答案可能令人难以置信,但实际上它可能不会有任何成本。如果你对数据库系统有所了解,那么你应该知道它们通常都很昂贵。相比之下,MySQL通常是可免费使用的。即便是在需要有技术支持和维护承诺保证的企业环境里,将MySQL作为数据库系统,其成本也是很低的。(想了解更多详情,请访问www.mysql.com。)我们将用到的其他工具(其中包括Perl、DBI、PHP和Apache)都是免费的。因此,综合考虑一下,你完全能够以相当低的成本组建一个有用的系统。

用于开发数据库的操作系统则由你来选择。几乎所有我们将讨论的软件都能在UNIX(它指代了BSD UNIX、Linux、Mac OS X等)和Windows上运行。极少数的例外情况一般是UNIX或Windows特有的shell脚本或批处理脚本。

1.2.2 成绩考评项目

现在一起来看另一个要使用示例数据库的情况。该项目的场景是:你是一名负责成绩考评的教师。你想将成绩处理工作,从使用成绩册的手工操作方式转换成使用MySQL的电子表示方式。在这种情况下,从数据库获取信息的方式隐含在你目前使用成绩册的方式中。

  • 对于每一次测验或考试,你都要记录分数。如果是考试,你还需要对分数进行排序,以便查看它们并确定每一个字母成绩(包括A、B、C、D和F)所代表的界线。
  • 在期末,你需要把计算出每一个学生的总分数,对这些总分数进行排序,并以此为基础确定出成绩。总分数可能需要加权计算,因为你可能需要让考试比测验的权重更大。
  • 在期末,你还要向学校办公室提供学生的考勤情况。

最终目标是要避免手动排序、避免手动汇总分数和考勤情况。换句话说,你希望MySQL可以对分数排序,并在期末完成所有与每个学生的总分和缺席次数相关的计算。为实现这些目标,你需要班里学生的名单、每次考试和测验的分数,以及全部学生的缺勤日期。

1.2.3 如何运用示例数据库

如果你对这里的“美史联盟”和“成绩考评”两个项目都不感兴趣,那么你可能会想“还有什么场景一定适合你呢”。答案就是“无穷无尽”。其实,这两个项目可以说明你用MySQL和与之相关的工具可以做什么事情。稍微想象一下,你便能看到示例数据库查询是如何应用于

你所要解决的那些特定问题的。假设你正好就在我前面提到的那个牙科诊所里工作。虽然在这本书里不会看到很多与牙科学有关的查询,但是会看到这里所发现的很多查询都可以应用到患者记录维护、办公记载等那些工作中。例如,“确定联盟里哪些成员需要更新他们的成员资格”与“确定最近哪些患者未来复诊”这两个任务便非常相似。它们都是基于日期的查询,因此只要你学会了“成员资格更新”的查询,那么便可以将该技巧用于编写“久未复诊患者”的查询,从而带来更多的收获。


1.3 基本数据库术语

你可能已经注意到了,尽管这是一本关于数据库的书籍,但到目前为止,你还未遇到过多少晦涩难懂的专业技术术语。事实上,尽管我们对如何使用示例数据库有过大致描述,但关于数据库到底是什么样子,我却只字未提。可是,既然我们要设计数据库,并实现它,那么我们就不能再避而不谈有关的术语了。这正是本节的主要内容。本节所描述的术语都是本书要用到的,因此希望大家能够熟悉它们。庆幸的是,关系数据库的许多概念都很简单。人们之所以喜欢关系数据库,很大程度上便是因为其基本概念都简明易懂。

1.3.1 结构术语

在数据库领域,MySQL被划分为关系数据库管理系统(RDBMS)。我们下面来拆解一下。

  • 数据库(DataBase,即RDBMS里的DB)是一个用来存储信息的仓库,它的结构简单、规则。

    • 数据库里的数据集都被组织成表(table)。

    • 每个表由多个行(row)和列(column)组成。

    • 表中的每一行称为一条记录(record)。

    • 记录可以包含多项信息;表里的每一列对应于其中的一项。

  • 管理系统(Management System,即RDBMS里的MS)是一个软件,我们可以通过它来插入(insert)、检索(retrieve)、修改(modify)或删除(delete)记录。

  • 关系(Relational,即RDBMS里的R)一词表示这是一种特殊的DBMS,其长处在于通过查找两个表里的共同元素,将分别存放于两个表里的信息联系(即匹配)起来。RDBMS的强大之处在于:它能方便地将这些表里的数据提取出来,并把相关表里的信息结合起来生成答案,回答那些只靠单个表无法回答的问题。(事实上,“关系”的正式定义与我在本书中用它的方式有所不同。为此,我先向那些纯粹主义者道歉。不过,我的定义更有助于表达出RDBMS的用途。)

关系数据库是如何把数据组织到表里的呢?又是如何把不同表的信息关联在一起的呢?下面来看一个例子。假设你在经营一个网站,它有一项横幅广告服务。你与多家想要刊登广告的公司签订了合同,满足它们想要在人们访问你网站页面时显示其广告的需要。每当有访客点击其中的某个页面时,你就提供一个嵌有广告的页面发送给访客浏览器,这样你就能从刊登这条广告的公司那里获得一点费用。这就是所谓的广告“点击”。为了表示这些信息,你需要用到3个表(见图1-1)。第1个company表由这样几列构成:公司名称、编号、地址和电话号码。第2个ad表的构成列有:广告编号、拥有该广告的那家公司的编号,以及每点击一次的收费数目。第3个hit表`需要记录广告点击量和广告点击日期。

图1-1 横幅广告的表

有些问题只用一个表便能回答。例如,想要知道与你签订了合同的公司有多少家,那么你只需统计一下company表共有多少行即可。同样地,想要了解在某段指定的时间里有多少点击量,则只需检查表hit即可。其他有些问题则可能比较复杂,需要查询多个表才能得到答案。例如,想要知道在7月14日那天Pickles公司(Pickles,Inc.)的每一条广告分别被点击了多少次,那么就需要像下面那样使用所有的3个表。

(1)在company表里查找公司名称(Pickles,Inc.),从而查出该公司的编号(14)。

(2)在ad表里,利用这个公司编号找出与之匹配的行,从而可以确定出所有相关广告的编号。最后找到两条广告,即编号48和101。

(3)对于在ad表里匹配到的每一行,使用该行里的广告编号在hit表里找出日期介于给定日期范围内的所有匹配行;然后,再统计这些匹配行的数量。最后查询出的结果是:48广告有3个匹配;101广告有2个匹配。

这些听起来好像很复杂!但这正是关系数据库系统最擅长做的事情。这种复杂性只是表面现象,因为刚才描述的每一步骤都是一个简单的匹配操作:将一个表的行值与另一个表的行值,通过匹配关联起来。这种简单的操作可以有多种变化,用于回答各式各样的问题,如各家公司分别投放了多少个不同的广告?哪家公司的广告最受欢迎?每个广告带来的收益是多少?在当前结算期内,各家公司应该支付你多少广告费?

有了之前讲述的这些关系数据库理论,你就能读懂本书后续的内容了;我们不必了解“第三范式”(Third Normal Form)、“实体联系图”(Entity-Relationship Diagram)等这些枯燥乏味的内容。(如果想了解它们,请阅读C. J. Date或E. F. Codd的著作。)

1.3.2 查询语言术语

为了与MySQL交互,需要使用一种名为SQL的语言。所有主流数据库系统都支持SQL,但各个服务商的实现都各不相同。SQL支持许多不同的语句,可以让你用非常有趣和实用的方式与数据库进行交互。

与其他计算机语言一样,初次接触SQL的人往往会觉得它很奇怪。例如,在创建表时,你必须告诉MySQL该表的结构是什么样子的。很多人都会想到把表与图表或图片联系起来。但是MySQL不是这样子的,因此在创建表时,你必须告知MySQL一些类似下面那样的内容:

CREATE TABLE company  
(  
  company_name VARCHAR(30),  
  company_num  INT,  
  address      VARCHAR(30),  
  phone        VARCHAR(12)  
);

如果对SQL还不太熟悉,那么可能会对这样的语句心生畏惧。不过请放心,你不用成为程序员就能学会如何熟练地使用SQL。随着对SQL的深入了解,你对CREATE TABLE的看法也会悄然地发生变化——它不再是一组怪诞的表达,而是一种有助于信息描述的强大工具。

1.3.3 MySQL的体系结构术语

当使用MySQL的时候,你实际上至少会用到两个程序,因为MySQL采用的是“客户端/服务器”体系结构。有一个程序是MySQL服务器,即mysqld。它运行在存放数据库的那台机器上,主要负责监听网络上的客户端请求,并根据这些请求去访问数据库内容,然后向客户端提供它们所查询的信息。另一个程序是MySQL客户端,它主要负责连接到数据库服务器,并发起查询,以便将自己想要的信息告知服务器。

MySQL的大部分发行版本都包括数据库服务器程序和客户端程序。(在Linux下使用RPM包时,会有一个单独的服务器RPM包和客户端RPM包,因此应该安装两种包。)请根据自己的实际情况使用合适的客户端程序。最常用的客户端程序是mysql,它是一个交互式客户端程序,你可以用它来发起查询并查看结果。另外还有两个主要用于管理的客户端程序,即mysqldump和mysqladmin。前者主要用来把表的内容导出到文件里;后者主要用来检查数据库服务器的工作状态,以及执行一些数据库管理相关的任务,如通知服务器关闭。MySQL发行版本里还包括一些其他的客户端程序。此外,MySQL还提供了一个客户端开发库,如果它自带的标准客户端程序无法满足你的应用需求,你可以利用这个库来编写自己的程序。这个开发库可以被C语言程序直接使用。如果你不习惯C语言,那么也可以选择适用于其他语言(如Perl、PHP、Python、Java和Ruby)的编程接口。

本书讨论的客户端程序都是基于命令行的。你也可以试试MySQL工作台(MySQL Workbench),这是一个基于图形用户界面(Graphical User Interface,GUI)的工具,提供了即点即击(point-
and-click)功能。关于此工具的更多信息,请访问http://www.mysql.com/products/
tools/。

MySQL的“客户端/服务器”体系结构有以下几个好处。

  • 服务器强制执行并发控制,可以防止两个用户同时修改同一条记录。所有客户端请求都要经过服务器,因此服务器会负责安排处理它们的先后顺序。即使出现多个客户端同时访问同一个表的情况,它们也不用先找到对方进行协商。它们只需把自己的请求发往服务器,然后由服务器来决定执行这些请求的顺序。
  • 不是只有在数据库所在的那台机器上才能登录。MySQL工作在网络环境里,因此你可以在任意地方运行MySQL客户端程序,它都能够通过网络连接到服务器。距离不是问题!你可以在世界的任何地方访问服务器。例如,你的服务器位于澳大利亚,那么就算你带着笔记本电脑旅行到了冰岛,你也仍然可以访问自己的数据库。这是否意味着任何人都能够通过互联网看到你的数据呢?答案是“不能”。MySQL有一套灵活的安全机制,你可以设定只有得到授权的人才能访问。此外,你还可以进一步限制这些人的操作。例如,财务部的Sally应该有查看和更新(修改)记录的权限;而服务台的Phil却只应该有查看记录的权限。总之,你可以把这种访问权限控制细化到每一个人。如果你只想运行一个自属的系统,那么你完全可以把访问权限设置为只允许服务器上的客户端程序进行连接。

MySQL与mysql之间的差异

为避免混淆,我们使用MySQL指代完整的MySQL RDBMS,而mysql指代特定客户端程序的名字。虽然它们的发音相同,但我们通过字母大小写和字体差异对它们进行了区分。

说到发音,MySQL被读作“my-ess-queue-ell”。具体细节可以在MySQL参考手册(MySQL Reference Manual)里查阅到。此外,SQL的读法有“sequel”和“ess-queue-ell”两种,具体是哪种由读它的人决定。本书假定SQL的发音为“ess-queue-ell”。


1.4 MySQL教程

现在你已具备了所有的预备知识。下面来实际操作一下MySQL。

本节提供了一个带有多个示例的教程,其目的在于帮助你熟悉MySQL。主要内容包括创建一个示例数据库和多个表,通过对这些表里的信息执行插入、检索、删除和修改操作,练习与示例数据库的交互。在此过程中,你将学会以下内容。

  • 了解MySQL所能理解的SQL基础知识。(MySQL与其他RDBMS所使用的SQL有所不同,因此你最好也能快速浏览一下本节的内容,从而确认一下MySQL的SQL实现与你熟悉的版本是否存在差异。)
  • 了解MySQL自带的标准客户端程序是如何与MySQL服务器进行通信的。前一节讲过,MySQL采用的是“客户端/服务器”体系结构。其中,服务器运行在数据库所在的机器上;而客户端则是通过网络连接到服务器。本教程主要依赖于客户端程序mysql,它首先读取你输入的SQL查询语句,把它们发送到服务器执行,然后把执行结果显示在你面前。客户端mysql可以在MySQL所支持的所有平台上运行,并且提供了与服务器进行交互的最直接的方式。不过根据需要,有些示例会使用mysqlimport或者mysqlshow来代替。

本书将示例数据库命名为sampdb。如果在你的系统上已经有人占用了这个名字,或者你的MySQL管理员为你分配了另一个名字,那么你需要换一个名字。不管是何种情况,你都需要把本书示例中的sampdb替换为你实际使用的数据库名称。

即使你的系统里有多个用户,且他们都各自拥有自己的示例数据库,本节所有示例里的表名也都可以直接使用。在MySQL里,只要每个人都用自己的数据库,那么大家完全可以使用相同的表名,不会有任何问题。MySQL将表限制在各自的数据库里,防止了相互干扰。

1.4.1 获取示例数据库发行包

本教程在好几个地方都要用到“示例数据库发行包”( 也称作“sampdb数据库的发行版”)。该发行包里包含了许多用来安装示例数据库的查询语句和数据。发行包的获取办法和安装步骤可以在附录A里查到。在发行包解压之后,它会自动创建一个名为sampdb的子目录,其中包含了你所需要的许多文件。顺便提个建议:每次你操作数据库里的示例时,最好都能切换到一个新的目录。

如果想要在任何目录里都可以方便地运行MySQL程序,那么你最好能把位于MySQL目录下包含着这些程序的bin目录,添加到命令解释器的搜索路径里。具体操作方法是,参考本书A.3.3节,把该目录的路径名称添加到环境变量PATH里

1.4.2 基本配置要求

为练习本教程里的各个示例,除获得示例数据库发行包外,还必须满足以下几项基本要求。

  • 必须安装MySQL软件。
  • 要有一个能够连接数据库服务器的MySQL账号。
  • 要有一个用来操作的数据库。

所需的软件包括MySQL客户端和MySQL服务器。客户端程序必须安装在你自己要用的机器里。服务器可以选择安装在你的机器上,这点不强求。只要你有权限连接它,那么服务器可以位于任何地方。如果你的因特网服务提供商(Internet Service Provider,ISP)提供了MySQL服务,那么也可以申请使用它。想要自己获得和安装MySQL,请参考附录A。

除了MySQL软件,还必须要有一个MySQL账户,这样才能连接到服务器,并创建示例数据库及其表。(如果你已有MySQL账户,则可以直接用它。不过,建议你另外建立一个专用于本书学习的账户。)

此时此刻,我们遇到了一个“是先有鸡,还是先有蛋”的难题:为了建立一个用于连接服务器的MySQL账户,你必须要先连接到该服务器。通常情况下,你需要在运行MySQL服务器的主机上,以root用户身份登录,然后执行CREATE USER语句GRANT语句来创建新的MySQL账户,并为其分配数据库权限。如果你是在自己的机器上安装了MySQL服务器,并且正在运行,那么你可以像下面那样用root身份连接服务器,然后创建一个新的示例数据库管理员账户,其用户名为sampadm,密码为secret。你也可以把其中的名字和密码更改成自己想用的,但在本书后面用到它们的地方也要做相应的修改。

% **mysql -p -u root  
**Enter password: ******  
mysql> **CREATE USER 'sampadm'@'localhost' IDENTIFIED BY 'secret';  
**Query OK, 0 rows affected (0.04 sec)  
mysql> **GRANT ALL ON sampdb.* TO 'sampadm'@'localhost';  
**Query OK, 0 rows affected (0.01 sec)

命令mysql有一个选项-p,它能让mysql提示输入root用户的MySQL密码。如上例所示,输入的密码会被显示为一串星号,即**。这里假设你已经为MySQL的root用户设置了密码。如果你还未设置,则请在Enter Password:提示出现后直接按回车(Enter)键。不过,如果root用户无密码,那么这是个很大的安全漏洞,你应该尽快给它设置一个。想要了解更多关于CREATE USER语句、GRANT语句、设置MySQL用户账户以及修改密码的信息,请参考第13章。

在创建sampadm账户之后,请输入quit,并按回车键,然后退出mysql``程序``。

刚才展示那些语句适合于在运行服务器的那台机器上连接MySQL。它们让你可以通过用户名sampadm和密码secret来连接服务器,并让你拥有完全访问sampdb数据库的权限。不过,GRANT语句并不会创建数据库(你可以在创建数据库之前为它分配权限)。我们稍后会讨论与数据库创建相关的操作。

如果你打算通过网络从另一台主机连接到MySQL服务器,那么需要把示例中的localhost更改为你正使用的那台主机的名字。例如,你想要从主机boa.example.com连接到MySQL服务器,那么相应的语句则应类似这样:

mysql> **CREATE USER 'sampadm'@'boa.example.com' IDENTIFIED BY 'secret';  
**mysql> **GRANT ALL ON sampdb.* TO 'sampadm'@'boa.example.com';**

如果你对服务器没有控制权限,无法创建用户,那么请求助MySQL管理员,让他为你建立一个账户。然后,将本书各示例里的samp admsecretsampdb分别替换为管理员分配给你的用户名、密码和数据库名。

1.4.3 建立和断开MySQL服务器连接

为连接到MySQL服务器,请在命令提示符(即Unix系统的shell提示符,或者Windows下的控制台窗口提示符)里调用mysql程序。命令如下:

% **mysql**options

本书使用%来表示命令提示符。它是Unix系统的其中一个标准提示符;另一个是$。在Windows系统里,你所看到的提示符有点像C:\&gt;。当输入这些示例里所示的命令时,请不要输入提示符本身。

mysql命令行里的options部分可以为空。但下面这种命令形式更为常见:

% **mysql -h**host_name**-p -u**user_name

在执行mysql时,不用提供所有的选项,但通常至少要指定用户名和密码。下面是全部选项的具体含义。

  • -h host_name(另一种形式是:--host=host_name

指定运行MySQL服务器的那台主机。如果它与你运行mysql程序的那台机器相同,就可以省略此选项。

  • -u user_name(另一种形式是:--user=user_name

指定MySQL用户名。如果你使用的是Unix系统,并且你的MySQL用户名与登录名完全一样,就可以省略此选项。mysql将自动将你的登录名当作MySQL用户名。

在Windows系统上,默认用户名为ODBC,它有可能无法使用。你可以在命令行通过-u选项来指定,也可以通过设置环境变量USER来添加一个默认用户名。例如,你可以用下面的set命令来指定一个用户名sampadm

C:\>** set USER=sampadm**

如果你通过控制面板(Control Panel)里的系统(System)项目设置环境变量USER,那么该设置对每一个控制台窗口都会起作用,你就不必在命令提示符里执行这条命令了。

  • -p(另一种形式是:--password

此选项会让mysql显示Enter password: 提示符,并要求你输入MySQL密码。例如:

% **mysql -h **host_name**-p -u**user_name
Enter password:

当你看到Enter password: 提示符时,请输入你的密码。(输入的密码不会显示到屏幕上,以免被人偷看到。)请注意:MySQL密码并不一定与登录Unix或Windows系统的密码相同。

如果你省略选项-p,那么mysql将认为你不需要密码,因此不会提示你输入它。

在命令行上直接提供密码的另一种方式是输入-pyour_pass选项(另一种形式是:--password=your_pass,其中的your_pass即为你的密码)。不过,出于安全的考虑,最好别这样做。因为在输入时,你身边的其他人能看到屏幕上的密码。另外,在Unix系统里,其他用户可能也能够使用系统工具查看到命令行。

如果你确实想要在命令行直接输入密码,那么请注意:在-p选项和后面的密码值之间没有空格。-p选项的这种行为经常会造成混乱,因为它与选项-h-u的习惯要求有所不同:它们都是与跟在后面的单词相关联的,不管其间是否有空格。

假设MySQL的用户名和密码分别是sampadmsecret。如果运行MySQL服务器的那台主机与你运行mysql程序的主机相同,那么你可以省略选项-h``, 此时mysql命令会像下面那样连接服务器:

% **mysql -p -u sampadm  
**Enter password: ******

在输入完这条命令之后,mysql会显示Enter password:``,提示你输入密码,然后你便可以输入它(输入的secret会在屏幕上显示为6个星号******)。

如果一切顺利,mysql将会显示出一条欢迎消息和一个mysql&gt;提示符,此时表明它在等你发起查询命令。完整的启动过程近似如下:

%** mysql -p -u sampadm  
**Enter password: ******  
Welcome to the MySQL monitor.  Commands end with ; or \g.  
Your MySQL connection id is 13762  
Server version: 5.5.30-log  

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.  

mysql>

如果想要连接运行于另一台机器上的MySQL服务器,那么必须使用-h选项来指定其主机名。假设该主机名为cobra.example.com,那么相应的命令如下所示:

% **mysql -h cobra.example.com -p -u sampadm**

为简洁起见,在后面大部分显示mysql命令行的示例里,选项-h-u-p都会被省略,并且假定你会提供所有必要的选项。在运行其他MySQL程序(如mysqlshow)时,你也会用到这些选项。

在连接到MySQL服务器之后,你可以随时输入quit命令来终止会话:

mysql> **quit**  
Bye

也可以输入exit\q来退出。在Unix系统里,可以按组合键Ctrl+D来退出。

在刚开始学习MySQL时,很多人都可能会对它的安全系统感到烦恼,因为它很难操作。(必须要有创建和访问数据库的权限;还有,不管何时连接服务器,都必须指定正确的用户名和密码。)不过,在练习完本书提供的示例数据库,并开始输入和使用自己的数据记录之后,你的看法便会迅速发生转变。到那时,你就会欣赏MySQL的这种方式,因为它可以防止他人窥视(或者更为糟糕的情况,破坏)你的信息。

如何设置工作环境,才能不用在每次运行mysql时都需要在命令行指定连接参数?关于这个问题请参考1.5节。简化服务器连接过程的最常见办法是,将连接参数存放到一个选项文件里。如果想现在就了解如何建立这样的文件,那么请直接跳转到1.5节。

1.4.4 执行SQL语句

在连接上服务器以后,你便可以发起SQL语句,让服务器执行它。本节将介绍一些与mysql``进行交互的一般原则。

想要在mysql里输入语句,只需要直接输入即可。在语句的结尾,请输入一个分号(;),并按下回车键。该分号会告知mysql——语句到此结束。在输入完一条语句之后,mysql会将它发送到服务器执行。服务器接着处理它,并把结果发送回mysql,然后mysql会显示结果。

下面这个示例展示了一条用于查询当前日期和时间的简单语句:

mysql> **SELECT NOW();**  
+---------------------+  
| NOW()               |  
+---------------------+  
| 2013-01-08 17:42:33 |  
+---------------------+  
1 row in set (0.00 sec)

除使用分号外,还有另一种终止语句的方法,即使用\g(意思是go):

mysql> **SELECT NOW()\g  
**+---------------------+  
| NOW()               |  
+---------------------+  
| 2013-01-08 17:42:40 |  
+---------------------+  
1 row in set (0.00 sec)

也可以使用\G。它会以“垂直”方式显示结果,每行显示一个值:

mysql> **SELECT NOW(), USER(), VERSION()\G  
***************************** 1. row ***************************  
    NOW(): 2013-01-08 17:54:24  
   USER(): sampadm@localhost  
VERSION(): 5.5.30-log  
1 row in set (0.00 sec)

如果语句的输出行比较短,那么\G就没什么用处;但如果输出行很长,而且会在屏幕上回绕显示,那么使用\G便能让输出内容更易于阅读。

如上所示,mysql会显示语句结果和一行统计信息,其中包括该结果所包含的行数,以及语句执行所花费的时间。在后面的示例里,一般情况下将不再显示统计信息行。

因为mysql会等待语句结束符,所以你不用在单独一行里输入一条语句的全部内容。你可根据需要,将它分隔成多行进行输入:

mysql> **SELECT NOW(),********  
**    -> **USER(),  
**    -> **VERSION()  
**    -> **;  
**+---------------------+-------------------+------------+  
| NOW()               | USER()            | VERSION()  |  
+---------------------+-------------------+------------+  
| 2013-01-08 17:54:56 | sampadm@localhost | 5.5.30-log |  
+---------------------+-------------------+------------+

请注意,在输入该语句的第一行时,提示符从mysql&gt;变为了-&gt;。这是在提醒你:mysql认为你还要继续输入语句内容。这是个很重要的反馈。如果你忘了在语句末尾加上分号,那么这个变化的提示符会提醒你注意:mysql仍在耐心等待你继续输入语句内容。否则,你会很不耐烦地等在一边,心里疑惑:为何MySQL执行你的语句要花这么长的时间。命令mysql还有另外几种提示符,附录F对它们进行了详细介绍。

如果你已经输入了一条多行语句,但突然决定不执行它了,那么可以输入\c来清除(即取消)它:

mysql>** SELECT NOW(),  
**    ->** VERSION(),  
**    ->** \c  
**mysql>

请注意,提示符是如何变回mysql&gt;的。这种变化表明mysql已准备接收一条新的语句。

与将一条语句分成多行输入相反的操作是,在单独一行里输入多条语句,两条语句中间用终止符隔开:

mysql> **SELECT NOW();SELECT USER();SELECT VERSION();  
**+---------------------+  
| NOW()               |  
+---------------------+  
| 2013-01-08 17:55:20 |  
+---------------------+  
+-------------------+  
| USER()            |  
+-------------------+  
| sampadm@localhost |  
+-------------------+  
+------------+  
| VERSION()  |  
+------------+  
| 5.5.30-log |  
+------------+

大多数情况下,输入语句使用大写、小写或者大小写混用都可以。例如,下面几条语句检索到的是相同的信息(虽然显示结果里列标题的大小写有所不同):

SELECT USER();  
select user();  
SeLeCt UsEr();

本书的所有示例都将用大写字母来表示SQL关键字和函数名,用小写字母来表示数据库、表和列的名字。

当在语句里调用函数时,请不要在函数名和后面的括号之间加入空格。如果有空格,则会导致语法错误。

将多条语句存储在一个文件里可以创建一个SQL脚本,然后让mysql从该文件(而不从键盘)读取语句。请使用shell的输入重定向功能来实现这种操作。例如,假设语句都存储在一个名为myfile.sql的文件里,那么我们可以使用下面这样的命令来执行其中的语句(请记得指定所有必需的连接参数选项):

% **mysql < myscript.sql**

你可以为该文件随便取一个名。我给它加上了一个“.sql”后缀,以表明里面存放的是SQL语句。

像这种调用mysql来执行文件里的语句的做法,会在1.4.7节再次用到,到时,我们会用这种办法来往sampdb数据库里输入数据。与逐条手工输入相比,让mysql从某个文件里读取多条INSERT语句来加载表要方便很多。

本教程的其余部分展示了很多SQL语句,你可以自行练习。在这些语句前面都有提示符mysql&gt;作为标志,并且这些示例都提供了语句输出结果。如果你输入与示例显示一样的语句,那得到的输出结果也应该是相同的。前面未加提示符的语句主要是用来做说明用的,你不需要执行它们。当然,如果愿意,执行一下也无妨。提醒一下,请记得在每条语句的末尾加上一个分号作为结束符。

1.4.5 创建数据库

数据库的使用涉及以下几个步骤。

(1)创建一个数据库。

(2)在该数据库里创建多个表。

(3)对表里的数据执行插入、检索、修改或删除操作。

想要创建新的数据库,请先使用mysql连接到服务器。然后执行CREATE DATABASE语句,并指定新的数据库名字:

mysql> **CREATE DATABASE sampdb;**

在创建可进入或对其内容进行操作的表之前,必须先创建sampdb数据库。

你可能会希望在创建某个数据库的同时,让它成为默认(或当前)数据库。但这是行不通的。看看下面这条检查默认数据库的语句,你就会明白这一点:

mysql> **SELECT DATABASE();  
**+------------+  
| DATABASE() |  
+------------+  
| NULL       |  
+------------+

NULL表示“未选择到数据库”。如果想要把sampdb设置为默认选择数据库,那么还需要执行一条USE语句:

mysql> **USE sampdb;  
**mysql> **SELECT DATABASE();  
**+------------+  
| DATABASE() |  
+------------+  
| sampdb     |  
+------------+

另一种选择默认数据库的办法是,调用mysql的时侯在命令行上给该数据库取一个名字:

% **mysql sampdb**

事实上,这就是在选择数据库时用得最多的办法。如果还需要使用连接参数,那么可以在命令行指定它们。例如,下面的命令可以让用户sampadm连接到本地主机(如果未指定主机名字,则默认是它)上的sampdb数据库:

%** mysql -p -u sampadm sampdb**

如果需要连接到运行于远程主机上的MySQL服务器,那么需要在命令行指定该主机:

% **mysql -h cobra.example.com -p -u sampadm sampdb**

如果无特别说明,后面所有的示例都将假定:当调用mysql时,命令行里指定的默认数据库就是sampdb。如果在调用mysql时忘记在命令行指定数据库,那么请在mysql&gt;提示符处输入一条USE sampdb语句。

1.4.6 创建表

本节将创建示例数据库sampdb所需要的那些表。首先,创建“美史联盟”场景所需要的表,然后,再为“成绩考评”项目创建所需的表。有些数据库书讲到在此处便会开始讨论“数据库的分析与设计”、“实体联系图”、“规范化过程”(Normalization Procedure)等内容。有很多书专门讲解这些内容,所以本书在这里只想说明我们的数据库应该是个什么样子,具体来讲涉及这样几个方面:它应该包含哪些表、每个表都应包含什么内容,以及在决定如何表示这些数据时需要考虑哪些问题。

这里所选择的表示方式并不是绝对的。在其他场合,你可以选用不同的方式来表示相似的数据。到底选择哪一种,需要由应用程序和数据的具体用途来决定。

1.4.6.1 美史联盟表

美史联盟的表相当简单,包括以下两个表。

  • president表。其中包含美国历任总统的描述性记录。我们需要用它来实现联盟网站上的在线小测验(对联盟通讯儿童专栏里出现的小测验进行交互式模拟)。
  • member表。用于保存联盟每位成员的最新个人资料。我们可以用它来创建成员名录的印刷版本和在线版本,用它来向到期成员自动发送提醒通知,还可以用它做很多其他事情。
1. president

president表包含一些与美国历任总统生平相关的基本信息。

  • 姓名。在表里,表示姓名的方式有好几种,如使用单列包含整个名字,或用不同的列分别表示姓(last name)和名(first name)。使用单列来表示当然更简单一些,但这种做法不够灵活,存在一些限制。

如果优先输入名,就无法按姓排序。

如果优先输入姓,就无法按名在前、姓在后的顺序显示它们。

难以查找姓名。例如,想要查找某人的姓,那么必须先使用一种模式,然后去查找与之匹配的姓名。与直接查找姓的做法相比,这种做法的效率很低,速度很慢。

为避免出现这些限制, president表将使用两列分别表示姓和名。

那个“名”列还要存放中间名或其缩写。这种做法不会影响到以后的姓名排序操作,因为我们不太可能对中间名进行排序(也不太可能对名进行排序)。另外,姓名也可以正常显示,因为无论是以“Bush, George W.”或“George W. Bush”中的哪一种格式来输出,姓名里的中间名总是排在名字的后面。

还有一点需要注意。如果一位总统(如Jimmy Carter)的姓名后面带有一个“Jr.”,那么这个“Jr.”应该放在哪里呢?根据英文姓名输出格式习惯,这位总统的名字可以显示为“James E. Carter, Jr.”,或者“Carter, James E., Jr.”。这里的“Jr.”与名和姓没有联系,因此我们还需要另外创建一个列,用它来保存姓名后缀。这种情况表明:当你在选择数据的表示形式时,即使只是一个单值,也可能会引发某些问题。它同时还表明:在把数据值放入数据库之前,最好尽可能多地对数据值进行深入的了解。如果对数据值的真正含义了解不够,那么在表启用之后,可能还要被迫更改它的结构。虽然这种事不能算作是一场灾难,但总的说来还是尽量避免为妙。

  • 出生地(城市和州)。与姓名的情况类似,它既可以用一列来表示,也可以用多列表示。采用单列来表示的做法显得更简单些;但与姓名的情况一样,使用多列能实现某些更复杂的操作。例如,若把州名与市名分开表示,那么像“找出出生在某个州的总统共有多少位”这种类似的操作便能轻易地实现。我们将使用两个单独的列来分别存放州名与市名。
  • 出生日期和逝世日期。这里唯一需要特殊处理的事情是:因为有些总统依然健在,所以我们不能要求必须填上逝世日期。特殊值NULL的意思即表示“无值”,因此我们可以在逝世日期列里用它来表示该位总统“依然健在”。
2. member

从每条记录都保存着单独某个人的个人资料这一角度来看,存放“美史联盟”成员列表的member表与刚才介绍的president表很相似。只是member表的每一行还包含了以下这些列。

  • 姓名。我们将沿用与president表相同的3列表示法:姓、名和姓名后缀。
  • ID编号。这是一个唯一值,为每个首次加入的成员分配一个。联盟此前从未对成员编过号,但现在需要所有的记录都更系统化,因此这里需要这个值。(希望你能不断发现MySQL的好处,并找到更多将编号应用于联盟记录的方式。当想要将member表里的行,与你所创建的成员相关的其他表建立关联时,使用编号则会比使用姓名更容易实现。)
  • 有效期。所有成员必须定期更新其成员资格,以避免过期。对于某些应用程序,可能还需要把最近一次资格更新后的起始日期存储起来,但“美史联盟”不需要这样做。成员资格的有效期是一个变值(通常有1年、2年、3年或者5年之分),而最近一次的资格更新日期也并不能说明该成员下一次的资格更新日期一定是在什么时候。因此,我们需要把成员资格的截止日期存储起来。此外,联盟还提供了终身成员资格。虽然我们可以用一个很遥远的日期来表示这种情况,但使用NULL会更合适,因为“无值”在逻辑上正好对应于“永不失效”。
  • 电子邮件地址。公开电子邮件地址可以使兴趣相投的成员交流起来更方便。作为联盟的秘书,在有了这些地址之后,就可以用电子邮件来向成员发送成员资格更新通知,而不用邮寄信件了。与到邮局寄信相比,这种做法既方便又省钱。你还可以利用电子邮件把每位成员的个人最新资料发送给他们,让他们在必要时更新信息。
  • 通信地址。当与那些没有电子邮件(或者长期没有回复你邮件)的成员进行联系时,你会需要这条信息。我们将使用多个列来分别存储街道地址、城市名、州名和邮政编码。

我们假设所有联盟成员都居住在美国。当然,对于那些成员遍布于世界各地的组织机构来说,这个假设可能显得有些简单。如果想要处理涉及多个国家的地址,那么你将遭遇到一些棘手的问题,必须要解决好不同国家所使用的地址格式不同的问题。例如,邮政编码就不是一项国际标准;另外,有很多国家都只有“省”的概念,而无“州”的说法。

  • 电话号码。与地址列相似,主要用于联系成员。
  • 特殊兴趣关键字。联盟的每位成员对美国历史肯定都很感兴趣,但他们的兴趣却可能集中于某些特定的历史时期。此列便是用于记录这些兴趣。每位成员都可以利用这些信息来寻找与自己兴趣相投的其他成员。(严格来讲,建立一个独立的表可能会更好些,表中的每一行都由一个关键字和相关成员的ID组成。这点有些复杂,我们暂不作处理。)
3. 创建美史联盟表

现在,我们准备创建美史联盟表。为此,我们需要使用CREATE TABLE语句,该语句具有以下格式:

CREATE TABLE tbl_name (column_specs);

其中,tbl_name指的是你要给表指定的名字;column_specs指的是该表的各列。该语句还会包括各种索引的定义,如果有的话。索引能够加快查找速度,关于这一点请参考第5章的介绍。

下面是针对president表的CREATE TABLE语句:

CREATE TABLE president  
(  
  last_name  VARCHAR(15) NOT NULL,  
  first_name VARCHAR(15) NOT NULL,  
  suffix     VARCHAR(5) NULL,  
  city       VARCHAR(20) NOT NULL,  
  state      VARCHAR(2) NOT NULL,  
  birth      DATE NOT NULL,  
  death      DATE NULL  
);

执行此语句的方法有两种:可以自己手动输入;也可以使用sampdb发行包中create_president.sql文件里包含的预先编写好的语句。

如果想要自已输入这条语句,那么请先调用mysql,同时将sampdb设置为默认数据库:

%** mysql sampdb**

接着,输入上面的CREATE TABLE语句。请记得在语句末尾输入分号,以便将这条语句的结束位置告知mysql程序。没有缩进格式也没有关系,你不用像上面那样换行。你完全可以在同一行输入整条语句。

如果想用预先编写好的描述来创建president表,那么可以使用sampdb发行包里的create_president.sql文件。当你解压发行包时,解压程序会自动创建一个sampdb目录,并将那个文件放在这个目录里。先进入该目录,然后执行下面这条命令:

% **mysql sampdb < create_president.sql**

无论你采用何种方式调用mysql,都请记得在命令行的命令名后面指定你可能需要的连接参数(其中包括主机名、用户名和密码)。

现在让我们来仔细看一下CREATE TABLE语句。该语句会为每一列指定列名、数据类型(列要存放的值的类型),以及可能有的某些列属性。

president表用到了两种数据类型:VARCHARDATEVARCHAR(n)表示的是:该列可以存放长度可变的字符型值,且最大长度为n个字符。也就是说,它们包含了长度不定的字符串,但其长度存在上限。那个n的值即表明了你所期望的数据长度。例如,将state定义为VARCHAR(2)类型,即表示我们需要以两个字母的缩写形式输入州名。而其他值为字符串类型列,其数据长度必须要再长一点才能容纳下更长的值。

我们用到的另一个数据类型是DATE。很显然,此类型表示该列用于保存日期值。不过,日期的表示格式可能会让你感到意外。MySQL要求将日期表示为'CCYY-MM-DD'格式,其中的CCYYMMDD分别代表了世纪、世界的年份、月和日。这也是SQL标准规定的日期表示格式(也叫做ISO 8601格式)。例如,想要在MySQL里指定“2013年7月18日”这样一个日期,则需要使用'2013-07-18'而不能用'07-18-2013''18-07-2013'`。

president表里,我们用到的列属性只有NULL(可以没有值)和NOT NULL(必须要有值)。大部分数据列的属性都为NOT NULL,因为我们要求它们必须要有值。可以有NULL属性的两列是:suffix(大部分总统的姓名都无后缀)和death(如果总统还健在,则无逝世日期)。

对于member表,其CREATE TABLE语句如下:

CREATE TABLE member  
(  
  member_id  INT UNSIGNED NOT NULL AUTO_INCREMENT,  
  PRIMARY KEY (member_id),  
  last_name  VARCHAR(20) NOT NULL,  
  first_name VARCHAR(20) NOT NULL,  
  suffix     VARCHAR(5) NULL,  
  expiration DATE NULL,  
  email      VARCHAR(100) NULL,  
  street     VARCHAR(50) NULL,  
  city       VARCHAR(50) NULL,  
  state      VARCHAR(2) NULL,  
  zip        VARCHAR(10) NULL,  
  phone      VARCHAR(20) NULL,  
  interests  VARCHAR(255) NULL  
);

与之前一样,你可以手动将这些语句输入mysql中,也可以利用预先编写好的文件。发行包sampdb中的creat_member.sql文件包含了member表的CREATE TABLE语句。要使用它,需要执行以下命令:

% **mysql sampdb < create_member.sql**

就数据类型而言,member表里的大部分列(有两个例外)的类型都很普通,都是可变长度的字符串类型。列member_idexpiration是例外,它们分别保存的是序号和日期。

使用成员资格编号列member_id的主要考虑是:为了避免成员之间产生混淆,其中每一个值都应该是唯一的。此时,AUTO_INCREMENT列正好可以派上用场,因为当我们添加新成员时,MySQL便能为我们自动生成一个唯一编号。虽然member_id列只是包含数字,但其定义却包含有好几个部分。

  • INT。它表示该列用于存放整数(无小数部分的数值)。
  • UNSIGNED。它表示该值不能为负数。
  • NOT NULL。它表示该列必须要填值,这可以防止创建的成员没有ID号。
  • AUTO_INCREMENT。它是MySQL的一个特殊属性,表示该列存放的是序号。AUTO_INCREMENT的工作原理为:当往member表里添加新记录时,如果没有为member_id列提供值,那么MySQL将自动生成下一个编号,并将它赋给该列。如果你显式地将NULL赋给该列,结果也是一样的。AUTO_INCREMENT的这种特性使得为每一位成员分配一个唯一的ID变得很简单,因为MySQL会替我们生成这些值。

PRIMARY KEY子句表示为member_id列创建索引,这样能加快查找速度。同时,它还设置了约束:要求该列里的所有值都必须唯一。后面这个属性正好符合对成员ID值的要求,因为它可以防止我们两次误用相同的ID。此外,MySQL要求AUTO_INCREMENT列必须有某种索引,如果没有索引,那么表的定义就是不合法的。(任何一个PRIMARY KEY列也必须是NOT NULL的,因此就算我们在member_id定义里省略了NOT NULL,MySQL也会自动加上。)

如果你还不太明白AUTO_INCREMENTPRIMARY KEY是怎么回事,那么可以把它们想象成一种能生成索引ID号的神奇魔法。这些值到底是什么并不重要,只要这些ID号对每位成员来说都是唯一的就可以了。(关于AUTO_INCREMENT列的更多信息请参考第3章。)

expiration列的数据类型是DATE。它允许值为NULL,且默认也为NULL,即表示可以不输入日期。正如前面所提到的,我们将使用这样一个约定:当expiration``值NULL时,表明该成员拥有终身成员资格。

到目前为止,你已经让MySQL创建了两个表,现在让我们来确认一下结果是否正确。在mysql里,调用下面这条命令可以查看president表的结构:

mysql> **DESCRIBE president;  
**+------------+-------------+------+-----+---------+-------+  
| Field      | Type        | Null | Key | Default | Extra |  
+------------+-------------+------+-----+---------+-------+  
| last_name  | varchar(15) | NO   |     | NULL    |       |  
| first_name | varchar(15) | NO   |     | NULL    |       |  
| suffix     | varchar(5)  | YES  |     | NULL    |       |  
| city       | varchar(20) | NO   |     | NULL    |       |  
| state      | varchar(2)  | NO   |     | NULL    |       |  
| birth      | date        | NO   |     | NULL    |       |  
| death      | date        | YES  |     | NULL    |       |  
+------------+-------------+------+-----+---------+-------+

调用DESCRIBE member语句,则可以看到有关member表的类似信息。(如果你想知道为什么未定义为允许NULLDefault列会显示NULL,那么我在这里告诉你,那是因为NULL也可用于表明该列没有显式的DEFAULT子句。)

如果你不记得一个表中的列名、想知道其数据类型,或者想了解其宽度是多少,那么可以使用DESCRIBE。你还可以利用它来查看MySQL在表行里存储各列的先后顺序。当你执行INSERTLOAD DATA语句时,这个顺序很重要,因为这些语句要求各列的值是以它们的默认列顺序列出的。

你也可以通过其他方式来获得DESCRIBE生成的信息。既可以是简写的DESC,也可以是EXPLAIN``语句SHOW语句。下面这些语句具有相同的作用:

DESCRIBE president;  
DESC president;  
EXPLAIN president;  
SHOW COLUMNS FROM president;  
SHOW FIELDS FROM president;

这些语句还允许对输出列加以限制。例如,可以在SHOW语句的末尾加上一个LIKE子句,这样便只能看到与给定模式相匹配的那些列的信息:

mysql> **SHOW COLUMNS FROM president LIKE '%name';  
**+------------+-------------+------+-----+---------+-------+  
| Field      | Type        | Null | Key | Default | Extra |  
+------------+-------------+------+-----+---------+-------+  
| last_name  | varchar(15) | NO   |     |         |       |  
| first_name | varchar(15) | NO   |     |         |       |  
+------------+-------------+------+-----+---------+-------+

使用``DESCRIBE president`` '%name'也可以得到同样的结果。这里用到的百分号(%)是一个特殊的通配符,我们将在后面的1.4.9 .7节中介绍它。

SHOW FULL COLUMNSSHOW COLUMNS很像,不同之处在于它会显示附加的列信息。你可以现在试一下,看看结果。

SHOW语句还有其他几种形式,可用于从MySQL获得不同类型的信息。SHOW TABLES语句会列出默认数据库里的表。到目前为止,我们已在数据库sampdb里创建了两个表,因此执行该语句将得到如下输出:

mysql> **SHOW TABLES;  
**+------------------+  
| Tables_in_sampdb |  
+------------------+  
| member           |  
| president        |  
+------------------+

SHOW DATABASES语句会列出当前连接到的服务器上的所有数据库:

mysql> **SHOW DATABASES;  
**+--------------------+  
| Database           |  
+--------------------+  
| information_schema |  
| mysql              |  
| sampdb             |  
| test               |  
+--------------------+

这个列表可能会因服务器不同而有所差异,但是应该能看到information_schemasampdb。其中,information_schema是一个事先存在的特殊数据库;而sampdb则是刚才创建的。另外还有一个数据库test,它是MySQL在安装过程中创建的。如果你的访问权限足够高,你可能还会看到名为

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值