SQL必知必会(第4版)(txt+pdf+epub+mobi电子书下载)


发布时间:2020-07-14 23:40:33

点击下载

作者:Ben Forta

出版社:人民邮电出版社

格式: AZW3, DOCX, EPUB, MOBI, PDF, TXT

SQL必知必会(第4版)

SQL必知必会(第4版)试读:

引言

SQL是使用最为广泛的数据库语言。不管你是应用开发者、数据库管理员、Web应用设计师、移动应用开发人员,还是只使用Microsoft Office,掌握良好的SQL知识对用好数据库都是很重要的。

本书可以说是应需而生。我讲授了多年的Web应用开发,学生们经常要求我推荐一些SQL图书。SQL方面的书很多,有的其实很不错,但它们都有一个共同的特点,就是讲授的内容太多了,多数人其实不需要了解那么多。很多图书讲的不是SQL本身,而是从数据库设计、规范化到关系数据库理论以及管理问题等,事无巨细都讲一通。当然,这些内容也很重要,但大多数读者仅想学习SQL,他们未必感兴趣。

因此,我找不到合适书籍推荐给学生,只好把在课堂上给学生讲授的SQL知识汇编成了本书。本书将讲授读者需要了解的SQL知识,从简单的数据检索入手,逐步过渡到一些较为复杂的内容,如联结、子查询、存储过程、游标、触发器以及表约束等。读者将从本书中循序渐进、系统而直接地学到SQL的知识和技巧。

本书写到了第4版,它已经教会了英语国家近30万的读者使用SQL,并且还翻译出版了十多种其他语言的版本。现在轮到你了,让我们翻到第1课,开始学习吧。你将很快编写出世界级的SQL。

读者对象

本书适合以下读者:● SQL新手;● 希望快速学会并熟练使用SQL;● 希望知道如何使用SQL开发应用程序;● 希望在无人帮助的情况下有效而快速地使用SQL。

本书涵盖的DBMS

一般来说,本书中所讲授的SQL可以应用到任何数据库管理系统(DBMS)。但是,各种SQL实现不尽相同,本书介绍的SQL主要适用于以下系统(需要时会给出特殊说明和注释):● Apache Open Office Base;● IBM DB2;● Microsoft Access;● Microsoft SQL Server(包括Microsoft SQL Server

Express);● MariaDB;● MySQL;● Oracle(包括Oracle Express);● PostgreSQL;● SQLite。

本书中的所有数据库示例(或者创建数据库示例的SQL脚本例子)对于这些DBMS都是适用的,它们可以在本书的网页http://forta.com/books/0672336073/上获得。

本书约定

本书采用等宽字体表示代码,读者输入的文本与应该出现在屏幕上的文本也都以等宽字体给出。如:It will look like this to mimic the way text looks on your screen.

变量和表达式的占位符用斜体表示,你可以用具体的值代替它。

代码行前的箭头()表示代码太长,上一行容纳不下。在符号后输入的所有字符都应该是前一行的内容。说明

给出上下文讨论中比较重要的信息。提示

就某任务给出建议或更简单的方法。注意

提醒可能出现的问题,避免出现事故。新术语

清晰定义重要的新词汇。

输入▼读者可以自己输入的代码,通常紧挨着代码出现。

输出▼强调某个程序执行时的输出,通常出现在代码后。

分析▼对程序代码进行逐行分析。

致谢

感谢Sams出版团队这些年来对我的支持、奉献和鼓励。特别要感谢Mark Taber,他促成了这本早就该更新的书,建议并帮助对书中的代码进行着色,更增加了新版的可读性,提升了书的价值。

感谢我的同事Greg Wilson,他为本书做了全面的技术审校。

感谢众多的读者对本书前三版提供的反馈。幸运的是,这些反馈多半是给与了我充分的肯定,在此深表感谢!这使得本版做了相应的改进和提高。欢迎大家对新版继续提出宝贵意见。

有好几十所学校将本书作为其IT和计算机科学课程的教材或参考书,在此特别表示感谢。能如此得到这些教授和老师的信任,对我是极大的鼓励,也让我诚惶诚恐。

最后,要感谢购买了本书前几版的接近30万的广大读者,你们使本书不仅成为我自己最畅销的一本书,而且也成为SQL方面最畅销的书之一。你们持续的支持是作者能得到的最宝贵的奖赏。——Ben Forta第1课了解SQL

这一课介绍SQL究竟是什么,它能做什么事情。1.1 数据库基础

你正在读这本SQL图书,这表明你需要以某种方式与数据库打交道。SQL正是用来实现这一任务的语言,因此在学习SQL之前,你应该对数据库及数据库技术的某些基本概念有所了解。

你可能还没有意识到,其实自己一直在使用数据库。每当你从电子邮件地址簿里查找名字时,就是在使用数据库。你在网站上进行搜索,也是在使用数据库。你在工作中登录网络,也需要依靠数据库验证用户名和密码。即使是在自动取款机上使用ATM卡,也要利用数据库进行密码验证和查询余额。

虽然我们一直都在使用数据库,但对究竟什么是数据库并不十分清楚。更何况人们可能会使用相同的数据库术语表示不同的事物,进一步加剧了这种混乱。因此,我们首先给出一些最重要的数据库术语,并加以说明。提示:基本概念回顾

后面是一些基本数据库概念的简要介绍。如果你已经具有一

定的数据库经验,可以借此复习巩固一下;如果你刚开始接

触数据库,可以由此了解必需的基本知识。理解数据库概念

是掌握SQL的重要前提,如果有必要,你或许还应该参阅其

他一些有关数据库基础知识的书籍 。1.1.1 数据库

数据库这个术语的用法很多,但就本书而言(从SQL的角度来看),数据库是一个以某种有组织的方式存储的数据集合。最简单的办法是将数据库想象为一个文件柜。这个文件柜是一个存放数据的物理位置,不管数据是什么,也不管数据是如何组织的。数据库(database)

保存有组织的数据的容器(通常是一个文件或一组文件)。注意:误用导致混淆

人们通常用数据库这个术语来代表他们使用的数据库软件,

这是不正确的,也因此产生了许多混淆。确切地说,数据库

软件应称为数据库管理系统(即DBMS)。数据库是通过

DBMS创建和操纵的容器,而具体它究竟是什么,形式如何,

各种数据库都不一样。1.1.2 表

你往文件柜里放资料时,并不是随便将它们扔进某个抽屉就完事了,而是在文件柜中创建文件,然后将相关的资料放入特定的文件中。

在数据库领域中,这种文件称为表。表是一种结构化的文件,可用来存储某种特定类型的数据。表可以保存顾客清单、产品目录,或者其他信息清单。表(table)

某种特定类型数据的结构化清单。

这里的关键一点在于,存储在表中的数据是同一种类型的数据或清单。决不应该将顾客的清单与订单的清单存储在同一个数据库表中,否则以后的检索和访问会很困难。应该创建两个表,每个清单一个表。

数据库中的每个表都有一个名字来标识自己。这个名字是唯一的,即数据库中没有其他表具有相同的名字。说明:表名

使表名成为唯一的,实际上是数据库名和表名等的组合。有

的数据库还使用数据库拥有者的名字作为唯一名的一部分。

也就是说,虽然在相同数据库中不能两次使用相同的表名,

但在不同的数据库中完全可以使用相同的表名。

表具有一些特性,这些特性定义了数据在表中如何存储,包含存储什么样的数据,数据如何分解,各部分信息如何命名等信息。描述表的这组信息就是所谓的模式(schema),模式可以用来描述数据库中特定的表,也可以用来描述整个数据库(和其中表的关系)。模式

关于数据库和表的布局及特性的信息。1.1.3 列和数据类型

表由列组成。列存储表中某部分的信息。列(column)

表中的一个字段。所有表都是由一个或多个列组成的。

理解列的最好办法是将数据库表想象为一个网格,就像个电子表格那样。网格中每一列存储着某种特定的信息。例如,在顾客表中,一列存储顾客编号,另一列存储顾客姓名,而地址、城市、州以及邮政编码全都存储在各自的列中。提示:分解数据

正确地将数据分解为多个列极为重要。例如,城市、州、邮

政编码应该总是彼此独立的列。通过分解这些数据,才有可

能利用特定的列对数据进行分类和过滤(如找出特定州或特

定城市的所有顾客)。如果城市和州组合在一个列中,则按

州进行分类或过滤就会很困难。你可以根据自己的具体需求来决定把数据分解到何种程

度。例如,一般可以把门牌号和街道名一起存储在地址里。

这没有问题,除非你哪天想用街道名来排序,这时,最好将

门牌号和街道名分开。

数据库中每个列都有相应的数据类型。数据类型(datatype)定义了列可以存储哪些数据种类。例如,如果列中存储的是数字(或许是订单中的物品数),则相应的数据类型应该为数值类型。如果列中存储的是日期、文本、注释、金额等,则应该规定好恰当的数据类型。数据类型

所允许的数据的类型。每个表列都有相应的数据类型,它限

制(或允许)该列中存储的数据。

数据类型限定了可存储在列中的数据种类(例如,防止在数值字段中录入字符值)。数据类型还帮助正确地分类数据,并在优化磁盘使用方面起重要的作用。因此,在创建表时必须特别关注所用的数据类型。注意:数据类型兼容

数据类型及其名称是SQL不兼容的一个主要原因。虽然大多

数基本数据类型得到了一致的支持,但许多高级的数据类型

却没有。更糟的是,偶然会有相同的数据类型在不同的

DBMS中具有不同的名称。对此用户毫无办法,重要的是在

创建表结构时要记住这些差异。1.1.4 行

表中的数据是按行存储的,所保存的每个记录存储在自己的行内。如果将表想象为网格,网格中垂直的列为表列,水平行为表行。

例如,顾客表可以每行存储一个顾客。表中的行编号为记录的编号。行(row)

表中的一个记录。说明:是记录还是行?

你可能听到用户在提到行时称其为数据库记录(record)。

这两个术语多半是可以交替使用的,但从技术上说,行才是

正确的术语。1.1.5 主键

表中每一行都应该有一列(或几列)可以唯一标识自己。顾客表可以使用顾客编号,而订单表可以使用订单ID。雇员表可以使用雇员ID或雇员社会安全号。主键(primary key)

一列(或一组列),其值能够唯一标识表中每一行。

唯一标识表中每行的这个列(或这几列)称为主键。主键用来表示一个特定的行。没有主键,更新或删除表中特定行就极为困难,因为你不能保证操作只涉及相关的行。提示:应该总是定义主键

虽然并不总是需要主键,但多数数据库设计者都会保证他们

创建的每个表具有一个主键,以便于以后的数据操作和管

理。

表中的任何列都可以作为主键,只要它满足以下条件:● 任意两行都不具有相同的主键值;● 每一行都必须具有一个主键值(主键列不允许NULL值);● 主键列中的值不允许修改或更新;● 主键值不能重用(如果某行从表中删除,它的主键不能赋给

以后的新行)。

主键通常定义在表的一列上,但并不是必需这么做,也可以一起使用多个列作为主键。在使用多列作为主键时,上述条件必须应用到所有列,所有列值的组合必须是唯一的(但单个列的值可以不唯一)。

还有一种非常重要的键,称为外键,我们将在第12课中介绍。1.2 什么是SQL

SQL(发音为字母S-Q-L或sequel)是结构化查询语言(Structured Query Language)的缩写。SQL是一种专门用来与数据库沟通的语言。

与其他语言(如英语或Java、C、PHP这样的编程语言)不一样,SQL中只有很少的词,这是有意而为的。设计SQL的目的是很好地完成一项任务——提供一种从数据库中读写数据的简单有效的方法。

SQL有如下的优点。● SQL不是某个特定数据库供应商专有的语言。几乎所有重要

的DBMS都支持SQL,所以学习此语言使你几乎能与所有数据库

打交道。● SQL简单易学。它的语句全都是由有很强描述性的英语单词

组成,而且这些单词的数目不多。● SQL虽然看上去很简单,但实际上是一种强有力的语言,灵

活使用其语言元素,可以进行非常复杂和高级的数据库操作。

下面我们将开始真正学习SQL。说明:SQL的扩展

许多DBMS厂商通过增加语句或指令,对SQL进行了扩展。

这种扩展的目的是提供执行特定操作的额外功能或简化方

法。虽然这种扩展很有用,但一般都是针对个别DBMS的,

很少有两个以上的供应商支持这种扩展。标准SQL由ANSI标准委员会管理,从而称为ANSI

SQL。所有主要的DBMS,即使有自己的扩展,也都支持

ANSI SQL。各个实现有自己的名称,如PL/SQL、Transact-

SQL 等。本书讲授的SQL主要是ANSI SQL。在使用某种DBMS特

定的SQL时,会特别说明。1.3 动手实践

与其他任何语言一样,学习SQL的最好方法是自己动手实践。为此,需要一个数据库和用来测试SQL语句的应用系统。

本书中所有课程采用的都是真实的SQL语句和数据表。附录A给出了具体的样例表,并介绍了获得(或创建)它们的详细步骤,便于读者理解每一课讲授的内容。附录B介绍在各种应用程序中执行SQL所需的步骤。在进入下一课之前,强烈建议读者先阅读这两个附录的内容,为以后的学习做好准备。1.4 小结

这一课介绍了什么是SQL,它为什么很有用。因为SQL是用来与数据库打交道的,所以,我们也复习了一些基本的数据库术语。

 第2课检索数据

这一课介绍如何使用SELECT语句从表中检索一个或多个数据列。2.1 SELECT语句

正如第1课所述,SQL语句是由简单的英语单词构成的。这些单词称为关键字,每个SQL语句都是由一个或多个关键字构成的。最经常使用的SQL语句大概就是SELECT语句了。它的用途是从一个或多个表中检索信息。关键字(keyword)

作为SQL组成部分的保留字。关键字不能用作表或列的名字。

附录E列出了某些经常使用的保留字。

为了使用SELECT检索表数据,必须至少给出两条信息——想选择什么,以及从什么地方选择。说明:理解例子

本书各课程中的样例SQL语句(和样例输出)使用了附录A

中描述的一组数据文件。如果想要理解和试验这些样例(我

强烈建议这样做),请参阅附录A,它解释了如何下载或创

建这些数据文件。重要的是,要理解SQL是一种语言而不是一个应用程序。

具体如何写SQL语句并显示语句输出,是随不同的应用程序

而变化的。为帮助读者根据自己的环境使用相应的例子,附

录B介绍了如何针对许多流行的应用程序及开发环境发出本

书中介绍的语句。如果读者需要了解某个应用程序,附录B

中也给出了相应的建议。2.2 检索单个列

我们将从简单的SQL SELECT语句讲起,此语句如下所示:

输入▼SELECT prod_nameFROM Products;

分析▼

上述语句利用SELECT语句从Products表中检索一个名为prod_name的列。所需的列名写在SELECT关键字之后,FROM关键字指出从哪个表中检索数据。此语句的输出如下所示:

输出▼prod_name-------------------Fish bean bag toyBird bean bag toyRabbit bean bag toy8 inch teddy bear12 inch teddy bear18 inch teddy bearRaggedy AnnKing dollQueen doll提示:未排序数据

如果你自己试验这个查询,可能会发现显示输出的数据顺序

与这里的不同。出现这种情况很正常。如果没有明确排序查

询结果(下一课介绍),则返回的数据没有特定的顺序。返

回数据的顺序可能是数据被添加到表中的顺序,也可能不

是。只要返回相同数目的行,就是正常的。

如上的一条简单SELECT语句将返回表中的所有行。数据没有过滤(过滤将得出结果集的一个子集),也没有排序。以后几课将讨论这些内容。提示:结束SQL语句

多条SQL语句必须以分号(;)分隔。多数DBMS不需要在

单条SQL语句后加分号,但也有DBMS可能必须在单条SQL

语句后加上分号。当然,如果愿意可以总是加上分号。事实

上,即使不一定需要,加上分号也肯定没有坏处。提示:SQL语句和大小写

请注意,SQL语句不区分大小写,因此SELECT与select是

相同的。同样,写成Select也没有关系。许多SQL开发人员

喜欢对SQL关键字使用大写,而对列名和表名使用小写,这

样做使代码更易于阅读和调试。不过,一定要认识到虽然

SQL是不区分大小写的,但是表名、列名和值可能有所不同(这有赖于具体的DBMS及其如何配置)。提示:使用空格

在处理SQL语句时,其中所有空格都被忽略。SQL语句可以

写成长长的一行,也可以分写在多行。下面这三种写法的作

用是一样的。

SELECT prod_name

FROM Products;

SELECT prod_name FROM Products;

SELECT

prod_name

FROM

Products;多数SQL开发人员认为,将SQL语句分成多行更容易阅

读和调试。2.3 检索多个列

要想从一个表中检索多个列,仍然使用相同的SELECT语句。唯一的不同是必须在SELECT关键字后给出多个列名,列名之间必须以逗号分隔。提示:当心逗号

在选择多个列时,一定要在列名之间加上逗号,但最后一个

列名后不加。如果在最后一个列名后加了逗号,将出现错误。

下面的SELECT语句从Products表中选择3列。

输入▼SELECT prod_id, prod_name, prod_priceFROM Products;

分析▼与前一个例子一样,这条语句使用SELECT语句从表Products中选择数据。在这个例子中,指定了3个列名,列名之间用逗号分隔。此语句的输出如下:

输出▼prod_id prod_name prod_price--------- -------------------- ----------BNBG01 Fish bean bag toy 3.4900BNBG02 Bird bean bag toy 3.4900BNBG03 Rabbit bean bag toy 3.4900BR01 8 inch teddy bear 5.9900BR02 12 inch teddy bear 8.9900BR03 18 inch teddy bear 11.9900RGAN01 Raggedy Ann 4.9900RYL01 King doll 9.4900RYL02 Queen dool 9.4900说明:数据表示

从上述输出可以看到,SQL语句一般返回原始的、无格式的

数据。数据的格式化是表示问题,而不是检索问题。因此,

表示(如把上面的价格值显示为正确的十进制数值货币金

额)一般在显示该数据的应用程序中规定。通常很少直接使

用实际检索出的数据(没有应用程序提供的格式)。2.4 检索所有列

除了指定所需的列外(如上所述,一个或多个列),SELECT语句还可以检索所有的列而不必逐个列出它们。在实际列名的位置使用星号(*)通配符可以做到这点,如下所示。

输入▼SELECT *FROM Products;

分析▼如果给定一个通配符(*),则返回表中所有列。列的顺序一般是列在表定义中出现的物理顺序,但并不总是如此。不过,SQL数据很少这样(通常,数据返回给应用程序,根据需要进行格式化,再表示出来)。因此,这不应该造成什么问题。警告:使用通配符

一般而言,除非你确实需要表中的每一列,否则最好别使用

*通配符。虽然使用通配符能让你自己省事,不用明确列出

所需列,但检索不需要的列通常会降低检索和应用程序的性

能。提示:检索未知列

使用通配符有一个大优点。由于不明确指定列名(因为星号

检索每一列),所以能检索出名字未知的列。2.5 检索不同的值

如前所述,SELECT语句返回所有匹配的行。但是,如果你不希望每个值每次都出现,该怎么办呢?例如,你想检索products表中所有产品供应商的ID:

输入▼SELECT vend_idFROM Products;

输出▼vend_id----------BRS01BRS01BRS01DLL01DLL01DLL01DLL01FNG01FNG01

SELECT语句返回9行(即使表中只有3个产品供应商),因为products表中有9种产品。那么如何检索出不同的值?

办法就是使用DISTINCT关键字,顾名思义,它指示数据库只返回不同的值。

输入▼SELECT DISTINCT vend_idFROM Products;

分析▼ SELECT DISTINCT vend_id告诉DBMS只返回不同(具有唯一性)的vend_id行,所以正如下面的输出,只有3行。如果使用DISTINCT关键字,它必须直接放在列名的前面。

输出▼vend_id----------BRS01DLL01FNG01警告:不能部分使用DISTINCT

DISTINCT关键字作用于所有的列,不仅仅是跟在其后的那

一列。例如,你指定SELECT DISTINCT vend_id, prod_price,

除非指定的两列完全相同,否则所有的行都会被检索出来。2.6 限制结果

SELECT语句返回指定表中所有匹配的行,很可能是每一行。如果你只想返回第一行或者一定数量的行,该怎么办呢?这是可行的,然而遗憾的是,各种数据库中的这一SQL实现并不相同。

在SQL Server和Access中使用SELECT时,可以使用TOP关键字来限制最多返回多少行,如下所示:

输入▼SELECT TOP 5 prod_nameFROM Products;

输出▼prod_name-----------------8 inch teddy bear12 inch teddy bear18 inch teddy bearFish bean bag toyBird bean bag toy

分析▼

上面代码使用SELECT TOP 5语句,只检索前5行数据。

如果你使用的是DB2,很可能习惯使用下面这一DBMS特定的SQL语句,像这样:

输入▼SELECT prod_nameFROM ProductsFETCH FIRST 5 ROWS ONLY;

分析▼

FETCH FIRST 5 ROWS ONLY就会按字面的意思去做的。

如果你使用Oracle,需要基于ROWNUM(行计数器)来计算行,像这样:

输入▼SELECT prod_nameFROM ProductsWHERE ROWNUM <=5;

如果你使用MySQL、MariaDB、PostgreSQL或者SQLite,需要使用LIMIT 子句,像这样:

输入▼SELECT prod_nameFROM ProductsLIMIT 5;

分析▼

上述代码使用SELECT语句来检索单独的一列数据。LIMIT 5指示MySQL等DBMS返回不超过5行的数据。这个语句的输出参见下面的代码。

为了得到后面的5行数据,需要指定从哪儿开始以及检索的行数,像这样:

输入▼SELECT prod_nameFROM ProductsLIMIT 5 OFFSET 5;

分析▼

LIMIT 5 OFFSET 5指示MySQL等DBMS返回从第5行起的5行数据。第一个数字是指从哪儿开始,第二个数字是检索的行数。这个语句的输出是:

输出▼prod_name-------------------Rabbit bean bag toyRaggedy AnnKing dollQueen doll

所以,LIMIT指定返回的行数。LIMIT 所带的 OFFSET指定从哪儿开始。在我们的例子中,Products表中只有9种产品,所以LIMIT 5 OFFSET 5只返回了4行数据(因为没有第5行)。警告:第0行

第一个被检索的行是第0行,而不是第1行。因此,LIMIT 1

OFFSET 1会检索第2行,而不是第1行。提示:MySQL和MariaDB捷径

MySQL和MariaDB支持简化版的LIMIT 4 OFFSET 3语句,即

LIMIT 3,4。使用这个语法,,之前的值对应OFFSET, ,之后

的值对应LIMIT。说明:并非所有的SQL实现都一样

我加入这一节只有一个原因,就是要说明,SQL虽然通常都

有相当一致的实现,但你不能想当然地认为它总是这样。非

常基本的语句往往是容易移植的,但较复杂的语句就不同

了。当你针对某个问题寻找SQL解决方案时,一定要记住这

一点。2.7 使用注释

可以看到,SQL语句是由DBMS处理的指令。如果你希望包括不进行处理和执行的文本,该怎么办呢?为什么你想要这么做呢?原因有以下几点。● 我们这里使用的SQL语句都很短,也很简单。然而,随着你

的SQL语句变长,复杂性增加,你就会想添加一些描述性的注释,

这便于你自己今后参考,或者供项目后续参与人员参考。这些注

释需要嵌入在SQL脚本中,但显然不能进行实际的DBMS处理。(相关示例可以参见附录B中使用的create.sql和populate.sql。)● 这同样适用于SQL文件开始处的内容,它可能包含程序员的

联系方式、程序描述以及一些说明。(相关示例也可参见附录B

中的那些.sql文件。)● 注释的另一个重要应用是暂时停止要执行的SQL代码。如果

你碰到一个长SQL语句,而只想测试它的一部分,那么应该注释

掉一些代码,以便DBMS将其视为注释而加以忽略。

很多DBMS都支持各种形式的注释语法。我们先来看行内注释:

输入▼SELECT prod_name -- 这是一条注释 FROM Products;

分析▼

注释使用-- (两个连字符)嵌在行内。-- 之后的文本就是注释,例如,这用来描述CREATE TABLE语句中的列就很不错。

下面是另一种形式的行内注释(虽然这种形式很少得到支持)。

输入▼# 这是一条注释SELECT prod_name FROM Products;

分析▼

在一行的开始处使用#,这一整行都将作为注释。你在本书提供的脚本create.sql和populate.sql中可以看到这种形式的注释。

你也可以进行多行注释,注释可以在脚本的任何位置停止和开始。

输入▼/* SELECT prod_name, vend_id FROM Products; */ SELECT prod_name FROM Products;

分析▼

注释从/*开始,到*/结束,/*和*/之间的任何内容都是注释。这种方式常用于给代码加注释,就如这个例子演示的,这里定义了两个SELECT语句,但是第一个不会执行,因为它已经被注释掉了。2.8 小结

这一课学习了如何使用SQL的SELECT语句来检索单个表列、多个表列以及所有表列。你也学习了如何返回不同的值,如何注释代码。同时不幸的是,更复杂的SQL使得SQL代码变得不轻便。下一课将讲授如何对检索出来的数据进行排序。

 第3课排序检索数据

这一课讲授如何使用SELECT语句的ORDER BY子句,根据需要排序检索出的数据。3.1 排序数据

正如上一课所述,下面的SQL语句返回某个数据库表的单个列。但请看其输出,并没有特定的顺序。

输入▼SELECT prod_nameFROM Products;

输出▼prod_name--------------------Fish bean bag toyBird bean bag toyRabbit bean bag toy8 inch teddy bear12 inch teddy bear18 inch teddy bearRaggedy AnnKing dollQueen doll

其实,检索出的数据并不是随机显示的。如果不排序,数据一般将以它在底层表中出现的顺序显示,这有可能是数据最初添加到表中的顺序。但是,如果数据随后进行过更新或删除,那么这个顺序将会受到DBMS重用回收存储空间的方式的影响。因此,如果不明确控制的话,则最终的结果不能(也不应该)依赖该排序顺序。关系数据库设计理论认为,如果不明确规定排序顺序,则不应该假定检索出的数据的顺序有任何意义。子句(clause)

SQL语句由子句构成,有些子句是必需的,有些则是可选的。

一个子句通常由一个关键字加上所提供的数据组成。子句的

例子有我们在前一课看到的SELECT语句的FROM子句。

为了明确地排序用SELECT语句检索出的数据,可使用ORDER BY子句。ORDER BY子句取一个或多个列的名字,据此对输出进行排序。请看下面的例子:

输入▼SELECT prod_nameFROM ProductsORDER BY prod_name;

分析▼除了指示DBMS软件对prod_name列以字母顺序排序数据的ORDER BY子句外,这条语句与前面的语句相同。结果如下。

输出▼prod_name--------------------12 inch teddy bear18 inch teddy bear8 inch teddy bearBird bean bag toyFish bean bag toyKing dollQueen dollRabbit bean bag toyRaggedy Ann ORDER BY子句的位置

在指定一条ORDER BY子句时,应该保证它是SELECT语句

中最后一条子句。如果它不是最后的子句,将会出现错误消

息。

 通过非选择列进行排序

通常,ORDER BY子句中使用的列将是为显示而选择的列。

但是,实际上并不一定要这样,用非检索的列排序数据是完

全合法的。3.2 按多个列排序

经常需要按不止一个列进行数据排序。例如,如果要显示雇员名单,可能希望按姓和名排序(首先按姓排序,然后在每个姓中再按名排序)。如果多个雇员有相同的姓,这样做很有用。

要按多个列排序,简单指定列名,列名之间用逗号分开即可(就像选择多个列时那样)。

下面的代码检索3个列,并按其中两个列对结果进行排序——首先按价格,然后按名称排序。

输入▼SELECT prod_id, prod_price, prod_nameFROM ProductsORDER BY prod_price, prod_name;

输出▼prod_id prod_price prod_name------- ---------- --------------------BNBG02 3.4900 Bird bean bag toyBNBG01 3.4900 Fish bean bag toyBNBG03 3.4900 Rabbit bean bag toyRGAN01 4.9900 Raggedy AnnBR01 5.9900 8 inch teddy bearBR02 8.9900 12 inch teddy bearRYL01 9.4900 King dollRYL02 9.4900 Queen dollBR03 11.9900 18 inch teddy bear

重要的是理解在按多个列排序时,排序的顺序完全按规定进行。换句话说,对于上述例子中的输出,仅在多个行具有相同的prod_price值时才对产品按prod_name进行排序。如果prod_price列中所有的值都是唯一的,则不会按prod_name排序。3.3 按列位置排序

除了能用列名指出排序顺序外,ORDER BY还支持按相对列位置进行排序。为理解这一内容,我们来看个例子:

输入▼SELECT prod_id, prod_price, prod_nameFROM ProductsORDER BY 2, 3;

输出▼prod_id prod_price prod_name------- ---------- --------------------BNBG02 3.4900 Bird bean bag toyBNBG01 3.4900 Fish bean bag toyBNBG03 3.4900 Rabbit bean bag toyRGAN01 4.9900 Raggedy AnnBR01 5.9900 8 inch teddy bearBR02 8.9900 12 inch teddy bearRYL01 9.4900 King dollRYL02 9.4900 Queen dollBR03 11.9900 18 inch teddy bear

分析▼

可以看到,这里的输出与上面的查询相同,不同之处在于ORDER BY子句。SELECT清单中指定的是选择列的相对位置而不是列名。ORDER BY 2表示按SELECT清单中的第二个列prod_price进行排序。ORDER BY 2,3表示先按prod_price,再按prod_name进行排序。

这一技术的主要好处在于不用重新输入列名。但它也有缺点。首先,不明确给出列名有可能造成错用列名排序。其次,在对SELECT清单进行更改时容易错误地对数据进行排序(忘记对ORDER BY子句做相应的改动)。最后,如果进行排序的列不在SELECT清单中,显然不能使用这项技术。按非选择列排序

显然,当根据不出现在SELECT清单中的列进行排序时,不

能采用这项技术。但是,如果有必要,可以混合使用实际列

名和相对列位置。3.4 指定排序方向

数据排序不限于升序排序(从A到Z),这只是默认的排序顺序。还可以使用ORDER BY子句进行降序(从Z到A)排序。为了进行降序排序,必须指定DESC关键字。

下面的例子以价格降序来排序产品(最贵的排在最前面):

输入▼SELECT prod_id, prod_price, prod_nameFROM ProductsORDER BY prod_price DESC;

输出▼prod_id prod_price prod_name------- ---------- --------------------BR03 11.9900 18 inch teddy bearRYL01 9.4900 King dollRYL02 9.4900 Queen dollBR02 8.9900 12 inch teddy bearBR01 5.9900 8 inch teddy bearRGAN01 4.9900 Raggedy AnnBNBG01 3.4900 Fish bean bag toyBNBG02 3.4900 Bird bean bag toyBNBG03 3.4900 Rabbit bean bag toy

如果打算用多个列排序,该怎么办?下面的例子以降序排序产品(最贵的在最前面),再加上产品名:

输入▼SELECT prod_id, prod_price, prod_nameFROM ProductsORDER BY prod_price DESC, prod_name;

输出▼prod_id prod_price prod_name------- ---------- --------------------BR03 11.9900 18 inch teddy bearRYL01 9.4900 King dollRYL02 9.4900 Queen dollBR02 8.9900 12 inch teddy bearBR01 5.9900 8 inch teddy bearRGAN01 4.9900 Raggedy AnnBNBG02 3.4900 Bird bean bag toyBNBG01 3.4900 Fish bean bag toyBNBG03 3.4900 Rabbit bean bag toy

分析▼DESC关键字只应用到直接位于其前面的列名。在上例中,只对prod_price列指定DESC,对prod_name列不指定。因此,prod_price列以降序排序,而prod_name列(在每个价格内)仍然按标准的升序排序。警告:在多个列上降序排序

如果想在多个列上进行降序排序,必须对每一列指定DESC

关键字。

请注意,DESC是DESCENDING的缩写,这两个关键字都可以使用。与DESC相对的是ASC(或ASCENDING),在升序排序时可以指定它。但实际上,ASC没有多大用处,因为升序是默认的(如果既不指定ASC也不指定DESC,则假定为ASC)。提示:区分大小写和排序顺序

在对文本性数据进行排序时,A与a相同吗?a位于B之前,

还是Z之后?这些问题不是理论问题,其答案取决于数据库

的设置方式。在字典(dictionary)排序顺序中,A被视为与a相同,

这是大多数数据库管理系统的默认行为。但是,许多DBMS

允许数据库管理员在需要时改变这种行为(如果你的数据库

包含大量外语字符,可能必须这样做)。这里的关键问题是,如果确实需要改变这种排序顺序,

用简单的ORDER BY子句可能做不到。你必须请求数据库管

理员的帮助。3.5 小结

这一课学习了如何用SELECT语句的ORDER BY子句对检索出的数据进行排序。这个子句必须是SELECT语句中的最后一条子句。根据需要,可以利用它在一个或多个列上对数据进行排序。

 第4课过滤数据

这一课将讲授如何使用SELECT语句的WHERE子句指定搜索条件。4.1 使用WHERE子句

数据库表一般包含大量的数据,很少需要检索表中的所有行。通常只会根据特定操作或报告的需要提取表数据的子集。只检索所需数据需要指定搜索条件(search criteria),搜索条件也称为过滤条件(filter condition)。

在SELECT语句中,数据根据WHERE子句中指定的搜索条件进行过滤。WHERE子句在表名(FROM子句)之后给出,如下所示:

输入▼SELECT prod_name, prod_priceFROM ProductsWHERE prod_price = 3.49;

分析▼这条语句从products表中检索两个列,但不返回所有行,只返回prod_price值为3.49的行,如下所示:

输出▼prod_name prod_price------------------- ----------Fish bean bag toy 3.49Bird bean bag toy 3.49Rabbit bean bag toy 3.49

这个示例使用了简单的相等检验:检查这一列的值是否为指定值,据此过滤数据。不过,SQL不止能测试等于,还能做更多的事情。提示:有多少个0?

你在练习这个示例时,会发现显示的结果可能是3.49、

3.490、3.4900等。出现这样的情况,往往是因为DBMS指定

了所使用的数据类型及其默认行为。所以,如果你的输出可

能与书上的有点不同,不必焦虑,毕竟从数学角度讲,3.49

和3.4900是一样的。

 提示:SQL过滤与应用过滤

数据也可以在应用层过滤。为此,SQL的SELECT语句为客

户端应用检索出超过实际所需的数据,然后客户端代码对返

回数据进行循环,提取出需要的行。通常,这种做法极其不妥。优化数据库后可以更快速有

效地对数据进行过滤。而让客户端应用(或开发语言)处理

数据库的工作将会极大地影响应用的性能,并且使所创建的

应用完全不具备可伸缩性。此外,如果在客户端过滤数据,

服务器不得不通过网络发送多余的数据,这将导致网络带宽

的浪费。

 警告:WHERE子句的位置

在同时使用ORDER BY和WHERE子句时,应该让ORDER

BY位于WHERE之后,否则将会产生错误(关于ORDER BY

的使用,请参阅第3课)。4.2 WHERE子句操作符

我们在做相等检验时看到了第一个WHERE子句,它确定一个列是否包含指定的值。SQL支持表4-1列出的所有条件操作符。

表4-1 WHERE子句操作符操作符说 明=等于< >不等于!=不等于<小于<=小于等于!<不小于>大于>=大于等于!>不大于BETWEEN在指定的两个值之间IS NULL为NULL值警告: 操作符兼容

表4-1中列出的某些操作符是冗余的(如< >与!=相同,!<相

当于>=)。并非所有DBMS都支持这些操作符。想确定你的

DBMS支持哪些操作符,请参阅相应的文档。4.2.1 检查单个值

我们已经看到了检验相等的例子,现在来看看几个使用其他操作符的例子。

第一个例子是列出所有价格小于10美元的产品:

输入▼SELECT prod_name, prod_priceFROM ProductsWHERE prod_price < 10;

输出▼prod_name prod_price------------------- ----------Fish bean bag toy 3.49Bird bean bag toy 3.49Rabbit bean bag toy 3.498 inch teddy bear 5.9912 inch teddy bear 8.99Raggedy Ann 4.99King doll 9.49Queen doll 9.49

下一条语句检索所有价格小于等于10美元的产品(因为没有价格恰好是10美元的产品,所以结果与前一个例子相同):

输入▼SELECT prod_name, prod_priceFROM ProductsWHERE prod_price <= 10;4.2.2 不匹配检查

这个例子列出所有不是供应商DLL01制造的产品:

输入▼SELECT vend_id, prod_nameFROM ProductsWHERE vend_id <> 'DLL01';

输出▼vend_id prod_name---------- ------------------BRS01 8 inch teddy bearBRS01 12 inch teddy bearBRS01 18 inch teddy bearFNG01 King dollFNG01 Queen doll提示:何时使用引号

如果仔细观察上述WHERE子句中的条件,会看到有的值括

在单引号内,而有的值未括起来。单引号用来限定字符串。

如果将值与字符串类型的列进行比较,就需要限定引号。用

来与数值列进行比较的值不用引号。

下面是相同的例子,其中使用!=而不是<>操作符:

输入▼SELECT vend_id, prod_nameFROM ProductsWHERE vend_id != 'DLL01';警告:是!=还是<>?

!=和<>通常可以互换。但是,并非所有DBMS都支持这两种

不等于操作符。例如,Microsoft Access支持<>而不支持!

=。如果有疑问,请参阅相应的DBMS文档。4.2.3 范围值检查

要检查某个范围的值,可以使用BETWEEN操作符。其语法与其他WHERE子句的操作符稍有不同,因为它需要两个值,即范围的开始值和结束值。例如,BETWEEN操作符可用来检索价格在5美元和10美元之间的所有产品,或在指定的开始日期和结束日期之间的所有日期。

下面的例子说明如何使用BETWEEN操作符,它检索价格在5美元和10美元之间的所有产品:

输入▼SELECT prod_name, prod_priceFROM ProductsWHERE prod_price BETWEEN 5 AND 10;

输出▼prod_name prod_price------------------- ----------8 inch teddy bear 5.9912 inch teddy bear 8.99King doll 9.49Queen doll 9.49

分析▼从这个例子可以看到,在使用BETWEEN时,必须指定两个值——所需范围的低端值和高端值。这两个值必须用AND关键字分隔。BETWEEN匹配范围中所有的值,包括指定的开始值和结束值。4.2.4 空值检查

在创建表时,表设计人员可以指定其中的列能否不包含值。在一个列不包含值时,称其包含空值NULL。NULL

无值(no value),它与字段包含0、空字符串或仅仅包含空

格不同。

确定值是否为NULL,不能简单地检查是否= NULL。SELECT语句有一个特殊的WHERE子句,可用来检查具有NULL值的列。这个WHERE子句就是IS NULL子句。其语法如下:

输入▼SELECT prod_nameFROM ProductsWHERE prod_price IS NULL;

这条语句返回所有没有价格(空prod_price字段,不是价格为0)的产品,由于表中没有这样的行,所以没有返回数据。但是,Customers表确实包含具有NULL值的列:如果没有电子邮件地址,则cust_email列将包含NULL值:

输入▼SELECT cust_nameFROM CustomersWHERE cust_email IS NULL;

输出▼cust_name----------Kids PlaceThe Toy Store提示:各DBMS特有的操作符

许多DBMS扩展了标准的操作符集,提供了更高级的过滤选

择。更多信息请参阅相应的DBMS文档。警告:NULL和非匹配

通过过滤选择不包含指定值的所有行时,你可能希望返回含

NULL值的行。但是这做不到。因为未知(unknown)有特

殊的含义,数据库不知道它们是否匹配,所以在进行匹配过

滤或非匹配过滤时,不会返回这些结果。过滤数据时,一定要验证被过滤列中含NULL的行确实

出现在返回的数据中。4.3 小结

这一课介绍了如何用SELECT语句的WHERE子句过滤返回的数据。我们学习了如何检验相等、不相等、大于、小于、值的范围以及NULL值等。

 第5课高级数据过滤

这一课讲授如何组合WHERE子句以建立功能更强、更高级的搜索条件。我们还将学习如何使用NOT和IN操作符。5.1 组合WHERE子句

第4课介绍的所有WHERE子句在过滤数据时使用的都是单一的条件。为了进行更强的过滤控制,SQL允许给出多个WHERE子句。这些子句有两种使用方式,即以AND子句或OR子句的方式使用。操作符(operator)

用来联结或改变WHERE子句中的子句的关键字,也称为逻

辑操作符(logical operator)。5.1.1 AND操作符

要通过不止一个列进行过滤,可以使用AND操作符给WHERE子句附加条件。下面的代码给出了一个例子:

输入▼SELECT prod_id, prod_price, prod_nameFROM ProductsWHERE vend_id = 'DLL01' AND prod_price <= 4;

分析▼此SQL语句检索由供应商DLL01制造且价格小于等于4美元的所有产品的名称和价格。这条SELECT语句中的WHERE子句包含两个条件,用AND关键字联结在一起。AND指示DBMS只返回满足所有给定条件的行。如果某个产品由供应商DLL01制造,但价格高于4美元,则不检索它。类似地,如果产品价格小于4美元,但不是由指定供应商制造的也不被检索。这条SQL语句产生的输出如下:

输出▼prod_id prod_price prod_name------- ---------- --------------------BNBG02 3.4900 Bird bean bag toyBNBG01 3.4900 Fish bean bag toyBNBG03 3.4900 Rabbit bean bag toyAND

用在WHERE子句中的关键字,用来指示检索满足所有给定

条件的行。

这个例子只包含一个AND子句,因此最多有两个过滤条件。可以增加多个过滤条件,每个条件间都要使用AND关键字。说明:没有ORDER BY子句

为了节省空间,也为了减少你的输入,我在很多例子里省略

了ORDER BY子句。因此,你的输出完全有可能与书上的输

出不一致。虽然返回行的数量总是对的,但它们的顺序可能

不同。当然,如果你愿意也可以加上一个ORDER BY子句,

它应该放在WHERE子句之后。5.1.2 OR操作符

OR操作符与AND操作符正好相反,它指示DBMS检索匹配任一条件的行。事实上,许多DBMS在OR WHERE子句的第一个条件得到满足的情况下,就不再计算第二个条件了(在第一个条件满足时,不管第二个条件是否满足,相应的行都将被检索出来)。

请看如下的SELECT语句:

输入▼SELECT prod_name, prod_priceFROM ProductsWHERE vend_id = 'DLL01' OR vend_id = ‘BRS01’;

分析▼此SQL语句检索由任一个指定供应商制造的所有产品的产品名和价格。OR操作符告诉DBMS匹配任一条件而不是同时匹配两个条件。如果这里使用的是AND操作符,则没有数据返回(因为会创建没有匹配行的WHERE子句)。这条SQL语句产生的输出如下:

输出▼prod_name prod_price------------------- ----------

试读结束[说明:试读内容隐藏了图片]

下载完整电子书


相关推荐

最新文章


© 2020 txtepub下载