第4章 走进SQL语句的世界
SQL(Structured Query Language)结构化查询语言,是一种数据库查询和程序设计语言,用于存取数据,及查询、更新和管理关系数据库系统。同时也是数据库脚本文件的扩展名。而T-SQL是标准SQL程序设计语言的增强版,它是用来让应用程序与SQL Server沟通的主要语言。本章以T-SQL为基础,从数据定义语句(DDL)、数据操作语句(DML)、数据控制语句(DCL)等方面介绍SQL及T-SQL的基本语法。本章的主要内容如下:
❑ 数据定义语句(DDL)。
❑ 数据操作语句(DML)。
❑ 数据控制语句(DCL)。
❑ 其他基本语句。
❑ 循环控制语句。
❑ 批处理语句。
有了前面这些必需的组件,就可以编写网站了,但是为了开发的方便和快捷,还需要一些辅助的开发工具,这样就可以更容易地构架起动态网站。
❑ Eclipse是不错的Java开发工具,配合第三方插件,可以更快捷地开发Web应用。
❑ Dreamweaver是一个可视化的页面编辑器,可以很方便地对页面结构进行设置和调整。
❑ MySQL Adiministrator是MySQL数据库服务器端的工具。
❑ MySQL Query Browser是MySQL数据库客户端的工具。
4.1 数据定义语句(DDL)
SQL是“结构化查询语言”(Structured Query Language)的简称,是由IBM的研究中心在1970年初期所开发的,是专门用于关联式资料库的一种查询语言。其中包括数据定义语句、数据操作语句、数据控制语句。数据定义语句DDL(Data Definition Language),是用于描述数据库中要存储的现实世界实体的语言。通常是数据库管理系统的一部分,用于定义数据库的所有特性和属性,尤其是行布局、列定义、键列(有时是选键方法)、文件位置和存储策略。常见的数据库定义语言包括CREATE DATABASE(创建数据库)、CREATE TABLE(创建表)、DROP VIEW(删除查询命令)、ALTER TABLE(修改数据表)等。下面我们将分别介绍各种数据定义语句。
4.1.1 CREATE的应用
CREATE是数据库操作语言中极其重要的一部分,也是经常要用到的一部分。其中包括数据库的创建、数据库表的创建及创建约束等,下面我们将举例熟悉CREATE的具体应用。
1.创建数据库
创建数据库,是指创建一个新数据库及存储该数据库的文件,或从先前创建的数据库的文件中附加数据库。包括数据库的名称、文件名称、数据文件大小、初始大小、是否自动增长等内容。在SQL Server 2005中,可以使用CREATE DATABASE语句创建数据库,也可以使用Management Studio工具通过图形界面完成数据库的创建。本章仅采用T-SQL语句来完成对数据库的操作。
CREATE DATABASE命令的语法格式如下:
CREATE DATABASE数据库名 [ON[PRIMARY] {([NAME=数据文件的逻辑名称] FILENAME='数据文件的物理名称' [SIZE=数据文件的初始大小] [MAXSIZE=数据文件的最大容量] [FILEGROWTH=数据文件的增长量])}[,…n]
各参数说明如下:
❑ database_name:数据库的名称,最长为128个字符。
❑ PRIMARY:该选项是一个关键字,指定主文件组中的文件。
❑ LOG ON:指明事务日志文件的定义。
❑ NAME:指定数据库的逻辑名称,这是在SQL Server系统中使用的名称,是数据库在SQL Server中的标识符。
❑ FILENAME:指定数据库所在文件的操作系统文件名称和路径,该操作系统文件名和NAME的逻辑名称一一对应。
❑ SIZE:指定数据库的初始容量大小,至少为模板Model数据库大小。
❑ MAXSIZE:指定操作系统文件可以增长到的最大尺寸。如果没有指定,则文件可以不断增长直到充满磁盘。
❑ FILEGROWTH:指定文件每次增加容量的大小,当指定数据为0时,表示文件不增长。
【例4-1】创建名称为test的数据库。
CREATE DATABASE test --创建名称为test的数据库 ON ( NAME = test_data, --数据库主数据文件名称为test_data FILENAME = 'D:\SQL Server 2005\test_data.mdf', --主数据文件存储位置 SIZE = 3, --SIZE参数没有指定MB或KB,因此默认为MB MAXSIZE = 5, --最大增长空间为5MB FILEGROWTH = 1 --文件每次的增长大小为1MB ) LOG ON --创建事务日志文件 ( NAME = test_log, FILENAME = ' D:\SQL Server 2005\ test_data_log', SIZE = 1MB, MAXSIZE = 2MB, FILEGROWTH = 1 ) GO
本实例定义了一个名为test的数据库,设定数据库主数据文件名称为test_data,大小为3MB,最大增长空间为5MB,每次增长1MB;事物文件名称为test_log,存放于D:\SQL Server 2005中,大小为1MB,最大为2MB,增量为1MB。
2.创建表
当完成对数据库的定义后,就需要根据自己的需求在创建的数据库中维持各个基本表的创建。创建表可以使用CREATE TABLE语句进行操作或者使用图形界面进行创建,在此仅以T-SQL语句为例进行简单介绍,其语法格式如下:
CREATE TABLE
database_name.[ owner ] .| owner.] table_name
( { < column_definition >| column_name AS computed_column_expression→
< table_constraint >} […n])
[ ON { filegroup | DEFAULT } ]
创建表的各参数的说明如下:
❑ database_name:用于指定在其中创建表的数据库名称。
❑ owner:用于指定新建表的所有者的用户名(可选)。
❑ table_name:用于指定新建表的名称。
❑ column_name:用于指定新建表的列的名称。
❑ computed_column_expression:用于指定计算列的列值的表达式。
❑ ON {filegroup → DEFAULT}:用于指定存储表的文件组名。
❑ TEXTIMAGE_ON:用于指定text、ntext和image列的数据存储的文件组。
❑ data_type:用于指定列的数据类型。
❑ DEFAULT:用于指定列的默认值。
【例4-2】在test中创建名称为teacher的信息表。
use test Create Table Teacher ( ID int Identity(1,1) not null, Name varchar(20) NOT NULL, Sex Char(2) null, Phone varchar(20) not null, Sallary smallmoney null, Address varchar(100) null, Email varchar(30) null )
执行此语句后将会在数据库test中增加一个名为teacher的表,表结构如图4.1所示。
图4.1 teacher表的结构
4.1.2 DROP的功能
DROP语句是数据库操作中不可或缺的一部分,通过使用DROP语句,可以轻松地删除索引、表和数据库。下面将通过实例进行删除数据库(DROP DATABASE)、删除表(DROP TABLE)的操作。
1.数据库的删除
当一个数据库不再使用时,可以将其删除。删除一个数据库会删除所有数据和该数据库所使用的磁盘文件,数据库在操作系统上占用的空间将被释放。但当删除一个数据库后,如果想再复原是很麻烦的,必须从备份中恢复数据库和它的事务日志。所以,删除数据库之前应格外小心。其语法如下:
DROP DATABASE <数据库名>
【例4-3】删除前面建立的名为test的数据库
DROP DATABASE test
2.数据库中表的删除
删除表即将指定的表从数据库中删除。在删除表后,所有属于表的数据、索引、视图、触发器将被自动删除,视图的定义仍被保留,但是无法使用(如果要删除的表是其他表的参照表,此表无法删除,需要先删除外键约束或者将其他表删除),其语法如下:
DROP TABLE <表名>
【例4-4】删除名为teacher的数据表。
DROP TABLE teacher
4.1.3 ALTER的功能
当数据库结构无法满足要求时,可以使用ALTER语句进行数据库及其内容表的修改。以下将以修改数据库(ALTER DATABASE)、修改表结构(ALTER TABLE)为例,对ALTER语句进行详细讲解。
1.修改数据库
ALTER DATABASE命令可以增加、删除数据库的文件及属性。但是此操作只有数据库管理员才可以进行操作。ALTER DATABASE语法如下:
Alter database databasename {add file<filespec>[,…n] [to filegroup filegroupname] |add log file <filespec>[,…n] |remove file logical_file_name [with delete] |modify file <filespec> |modify name=new_databasename |add filegroup filegroup_name |remove filegroup filegroup_name |modify filegroup filegroup_name {filegroup_property→name=new_filegroup_name}}
其具体功能如下:
❑ 增加(add)数据库文件(file)、日志文件(log file)、文件组(filegroup)。
❑ 删除(remove)数据文件(file)、文件组(filegroup)。
❑ 修改(modify)数据库名称(name=new_databasename)、文件(file)、文件组(filegroup)。
【例4-5】修改数据库books的名称为library。
ALTER DATABASE books modify name = livrary
2.修改表
修改表结构,是指对已定义的表增加新的列或删除多余的列。这些都是用ALTER TABLE实现。但是也有特殊情况:当一个表中有主关键字的列,就不能再次向此表中添加有主关键字的列;如果要为列设置唯一性约束,此列不能包括空值。
ALTER TABLE语法为:
ALTER TABLE [ [ database_name . ] owner.]table_name [ WITH NOCHECK ] ADD { [ column_name datatype [ column_constraints ] | [ [ , ] table_constraint ] ] } [, [ { next_col_name → next_table_constraint } ] …] } | DROP [constraint_name [,…n ]
其具体功能如下:
❑ 向表中增加列,并可在新添加的列上增加列完整性约束。
❑ 删除表中指定的列。
【例4-6】向books表中增加一列price,其数据类型为货币(money)型。
ALTER TABLE books ADD price money default 23.8
【例4-7】将表books中的price列删除。
ALTER TABLE BOOKS DROP COLUMN price
4.2 数据操作语句(DML)
数据操作语句(DML,Data Manipulation Language)是使用户能够查询数据库及操作已有数据库中数据的计算机语言,在SQL语言中占据着非常重要的地位。其包括数据的插入(INSERT)、数据的删除(DELETE)、数据的更改(UPDATE)、数据的查询(SELECT)等内容。
4.2.1 数据的插入——INSERT
向一个已经存在的表中插入数据,可以分为一次插入一条记录,也可以分为一次插入多条记录。但是需要注意的是,无论哪种方式,输入的数据都必须符合数据类型及其相应的约束。其语法结构如下:
INSERT [ INTO] table_name <VALUES( { DEFAULT | NULL | expression } [ ,…n] --输入一条信息> <嵌套子查询--插入一组元组>
【例4-8】向student表中插入一条新生信息。
Insert into student values (01,'王明','男', '1980-1-1') --插入一条记录 select * from student where student_id = 01
运行代码,结果如图4.2所示。
图4.2 插入一条student记录
【例4-9】将不慎插错到另一个表teacher中的数据转到student表中。
Insert into student select * from teacher select * from student
运行代码,结果如图4.3所示。
图4.3 插入一条student记录
4.2.2 数据的删除——DELETE
删除表中的数据,是指在表中删除记录,但是表的结构、约束、索引等并没有删除。删除数据可以分为按指定条件删除一个或者多个元组,也可以不指定条件对数据表中所有元组进行删除,甚至可以运用子查询的结果进行删除。
1.按照指定条件删除一个或者多个元组
语法格式如下:
DELETE FROM < table_name > WHERE < search_condition >
【例4-10】删除student表中student_id为1的学生信息。
DELETE STUDENT WHERE STUDENT_ID = 1 SELECT * FROM STUDENT WHERE STUDENT_ID = 1
运行代码,结果如图4.4所示。
图4.4 删除一条student记录
2.删除表中所有元组
语法格式如下:
DELETE [FROM] < table_name >
【例4-11】删除student表中所有记录。
DELETE STUDENT SELECT * FROM STUDENT
运行代码,结果如图4.5所示。
图4.5 删除student表中所有记录
4.2.3 数据的更改——UPDATE
UPDATE语句允许用户在已知的表中对现有的行进行修改。修改数据有以下几种方式:可以按指定条件修改一个或者多个元组,也可以修改表中所有元组,甚至可以利用子查询的结果进行数据的修改。
1.按指定条件修改数据
语法格式如下:
UPDATE { table_name WITH ( < table_hint_limited > [ …n ] )} SET { column_name = {expression → DEFAULT | NULL } WHERE < search_condition >
【例4-12】更新student表中student_id为1的学生性别为“女”。
UPDATE STUDENT SET SEX = '女' WHERE STUDENT_ID = 1 SELECT * FROM STUDENT WHERE STUDENT_ID = 1
运行代码,结果如图4.6所示。
图4.6 修改student表中student_id为1的学生性别为“女”
2.修改表中所有元组
语法格式如下:
{ table_name WITH ( < table_hint_limited > [ …n ] )} SET { column_name = {expression | DEFAULT | NULL }
【例4-12】更新Books表中ISREAD的值为“1”(即true)。
UPDATE BOOKS SET ISREAD = 'true' SELECT * FROM BOOKS
运行代码,结果如图4.7所示。
图4.7 修改Books表中所有ISREAD元组
4.2.4 数据的查询——SELECT
数据查询是数据库编程中最基本并且也是最常用的一部分,对用户来说,数据查询是数据库最重要的功能。SQL Server的数据查询使用T-SQL语言,其最基本的语句是SELECT语句。SELECT语句的功能相当强大,下面讲述数据查询的实现方法。
1.SELECT语句的结构
SELECT的语法比较烦琐,下面先列出SELECT语句的语法,其用法将在后面详细说明。
SELECT语句的语法如下:
SELECT [ALL→DISTINCT] <目标列表达式> [<目标列表达式>] … FROM <表名或视图名>[ <表名或视图名> ] … [ WHERE <条件表达式> ] [ GROUP BY <列名1> [ HAVING <条件表达式> ] ] [ ORDER BY <列名2> [ ASC|DESC ] ]
SELECT语句的含义是,根据WHERE子句指定的条件,从FROM子句后面的基本表或视图中找出满足条件的记录,再按照SELECT子句指定的目标列表达式,选出这些记录相应的列形成结果集返回。
其中,SELECT子句和FROM子句是必选的,而WHERE子句、GROUP BY子句、HAVING子句及ORDER BY子句都是可选择的。
重点语法结构解析。
❑ GROUP BY<列名>:指定根据列名进行分类汇总查询。
❑ ORDER BY <列名> [ ASC/DESC ]:将查询结果按列名指定的顺序排列(ASC——升序, DESC——降序)。
2.基本SELECT查询
最基本的SELECT语句语法格式:
SELECT [ALL|DISTINCT] <目标列表达式> [<目标列表达式>] … FROM <表名或视图名>[ <表名或视图名> ] …
【例4-13】查询Books表中所有图书的信息。
USE LIB --打开数据库lib select * from books --查询所有图书信息
运行代码,结果如图4.8所示。
图4.8 查询Books表中所有图书信息
Tips
“*”代表所有。查询表中所有列不必全部列出,可以用“*”代替。
3.带有限制条件的SELECT查询
在我们要选取符合条件的某些列时,所以就不能用“*”来查询,并且“*”查询的效率也是极低的。所以在查询列表时应该尽量指定列名,以使查询语句更可读,效率更高。
【例4-14】查询Books表中图书的名字和价格。
--打开数据库lib USE LIB --查询图书的名字和价格 select book_name,price from books
运行代码,结果如图4.9所示。
图4.9 查询Books表中图书的名字和价格
4.表达式在查询列表中的使用
【例4-13】查询Books图书打八折后的价格。
--打开数据库lib USE LIB --查询所有图书的名字,价格,八折后价格 select book_name,price,price*0.8 as newprice from books
运行代码,结果如图4.10所示。
图4.10 查询Books表使用列计算表达式的信息
Tips
as关键字:列名表达式后的关键字as接一个字符串来为列表达式指定列名,关键字as也可以省略。
5.取得查询结果的部分行集
TOP子句限制返回结果集中的行数,语法如下:
TOP N [PERCENT]
N指返回的行数,PERCENT指返回结果集的百分比。
【例4-14】一个拥有大量数据的数据库hosts,只显示前10条记录。
USE preEdu --打开数据库 SELECT TOP 10 * FROM HOSTS --查询前10条记录
运行代码,结果如图4.11所示。
图4.11 查询hosts表中前10条记录
6.使用逻辑表达式NOT(非)进行查询
NOT用于单个关系表达式前,与关系表达式的结果相反。因此只有当关系表达式的值为假时,其整个结果为真。
【例4-15】在Books表中,查询所有价格(price)小于40的图书信息。
USE LIB --打开数据库LIB SELECT * FROM BOOKS WHERE NOT (PRICE>40) --查询所有price小于40的图书信息
运行代码,结果如图4.12所示。
图4.12 查询Books表中所有价格小于40的图书信息
7.使用逻辑表达式AND(与)进行查询
AND连接两个关系表达式,只有两个表达式都成立结果才为真。
【例4-16】在Books表中,查询所有价格(price)小于40大于20的图书信息。
USE LIB --打开数据库LIB SELECT * FROM BOOKS WHERE PRICE<40 AND PRICE>20 --查询所有price小于40大于20的图书信息
运行代码,结果如图4.13所示。
图4.13 查询Books表中所有价格小于40大于20的图书信息
8.使用逻辑表达式OR(或)进行查询
OR(或)表达式只要两个关系表达式满足其一,其结果就为真。
【例4-17】在Books表中,查询所有价格(price)大于40或小于20的图书信息。
USE LIB --打开数据库LIB SELECT * FROM BOOKS WHERE PRICE>40 OR PRICE<20 --查询所有price大于40或小于20的图书信息
运行代码,结果如图4.14所示。
图4.14 查询Books表中价格大于40或小于20的图书信息
9.使用通配符进行模糊查询
当进行查询时,大部分时间查询条件是确定的,这样可以根据查询条件很容易地得出结果,但是有些时候要查询的条件并非准确,这样就必须根据需要进行模糊查询了。模糊查询使用LIKE运算符可完成字符串的模糊匹配,匹配字符串可使用通配符,其具体含义如表4.1所示。
表4.1 通配符含义
【例4-18】在student表中,查询所有姓“高”的学生信息。
USE STUDENTS --打开数据库LIB SELECT * FROM STUDENT WHERE 姓名LIKE '高%' --查询所有姓“高”的学生信息
运行代码,结果如图4.15所示。
图4.15 查询student表中所有姓“高”的学生信息
【例4-19】在student表中,查询所有姓介于陈-高并且肖-赵的学生信息。
USE STUDENTS --打开数据库LIB SELECT * FROM student WHERE 姓名LIKE '[陈-高,肖-赵]%' --查询所有姓介于陈-高并且肖-赵的学生信息
运行代码,结果如图4.16所示。
图4.16 查询student表中所有姓介于陈-高并且肖-赵的学生信息
10.使用BETWEEN…AND关键字进行查询
在前面提到了使用逻辑表达式完成数据查询,现在使用BETWEEN关键字进行查询,其语法格式为:
BETWEEN条件一 AND条件二
使用BETWEEN完成例4-16的查询。
【例4-20】在Books表中,查询所有价格(price)小于40大于20的图书信息。
USE LIB --打开数据库LIB SELECT * FROM BOOKS WHERE PRICE BETWEEN 20 AND 40 --查询所有price小于40大于20的图书信息
运行代码,结果如图4.17所示。
图4.17 查询Books表中所有价格小于40大于20的图书信息
11.查询排序
通常,数据库中的数据是无序显示的,但是在很多情况下为了突出某种效果,我们希望数据记录按照一定的顺序显示,这时我们就要用到ORDER BY语句,其语法如下:
SELECT语句的语法如下:
SELECT [ALL|DISTINCT] <目标列表达式> [<目标列表达式>] … FROM <表名或视图名>[ <表名或视图名> ] … [ WHERE <条件表达式> ] [ ORDER BY <列名2> [ ASC|DESC ] ]
【例4-21】在Books表中,将所有图书按价格高低的顺序排列。
USE LIB --打开数据库LIB SELECT * FROM BOOKS ORDER BY PRICE ASC --将所有图书按价格高低的顺序排列
运行代码,结果如图4.18所示。
图4.18 将Books表中记录按照图书价格高低的顺序排列
4.3 数据控制语句(DCL)
数据控制语言(DCL)是用来设置、更改数据库用户或角色权限的语句,包括GRANT、DENY、REVOKE等语句,在默认状态下,只有sysadmin、dbcreator、db_owner或db_securityadmin等角色的成员才有权利执行数据控制语言。
4.3.1 如何给用户授予权限——GRANT
当用户成为数据库中的合法用户后,只具有可以查询系统表的权限,而不具有操作数据库中对象的任何权限,因此,需要给数据库中的用户授予操作数据库对象的权限。
通常,SQL Server对权限的管理包含3方面内容即授予权限、收回权限、拒绝权限。
以下我们将简要介绍GRANT的作用,详细内容后面会专门介绍。
对象权限是指用户对数据库的表、视图等对象的操作权,相当于数据操作语言的语句权限,如是否进行查询、增加、删除等。下面举例说明GRANT(授权语句)的运用。
【例4-22】将student表的查询权和插入权授予用户sa1,sa1同时获得将这些权限转授给别的用户的权限。
GRANT SELECT,INSERT ON student TO sa1 WITH GRANT OPTION
4.3.2 拒绝权限操作——DENY
在很多时候,有些表并不是想让每个人来查看的,此时可以使用SQL新特性DENY来禁止此表的SELECT权限。DENY可以被管理员用来禁止某个用户对一个对象的所有访问权限。下面通过一个实例来加深对此语句的使用。
【例4-23】拒绝sa1用户对student表进行修改操作。
DENY UPDAT ON student TO sa1
4.3.3 收回权限操作——REVOKE
当要对一个用户取消特权,如插入权限、查询权限、删除权限等,就要使用T-SQL语句进行收回权限操作。T-SQL语言提供了REVOKE语句来实现此功能。具体实例如下:
【例4-24】收回sa1用户对student表的插入权。
REVOKE INSERT ON student FROM sa1 CASCADE
CASCADE表示收回权限时要引起连锁回收。此节内容将会在提高篇具体介绍,因此在此不作过多介绍。
4.4 其他基本语句
SQL中除了数据定义语句、数据操作语句、数据控制语句外还有其他一些基本语句,以此来辅助语句的执行。在此,将介绍DECLARE、SET、PRINT等几个基本语句来熟悉语句的应用和操作。
4.4.1 数据声明——DECLARE
DECLARE命令用于声明一个或多个局部变量、游标变量、函数、过程等。在用DECLARE命令声明后所有的变量被赋值NULL,需要用SET或者SELECT赋值。具体语法如下:
语法1:
[Public | Private] Declare Sub name Lib "libname" [Alias "aliasname"] [([arglist])]
语法2:
[Public | Private] Declare Function name Lib "libname" [Alias "aliasname"] [([arglist])] [As type]
语法参数详解:
❑ Public:可选的。用于声明对所有模块中的所有其他过程都可以使用的过程。
❑ Private:可选的。用于声明只能在包含该声明的模块中使用的过程。
❑ Sub:可选的(但Sub或Function二者需选其一)。表示该过程没有返回值。
❑ Function:可选的(但Sub或Function二者需选其一)。表示该过程会返回一个可用于表达式的值。
❑ name:必需的。任何合法的过程名。注意在动态链接库的入口处(entry points)区分大小写。
❑ Lib:必需的。指明包含所声明过程的动态链接库或代码资源。所有声明都需要Lib子句。
❑ libname:必需的。包含所声明过程的动态链接库名或代码资源名。
❑ Alias:可选的。表示将被调用的过程在动态链接库 (DLL) 中还有另外的名称。当外部过程名与某个关键字重名时,就可以使用这个参数。当动态链接库的过程与同一范围内的公用变量、常数或任何其他过程的名称相同时,也可以使用Alias。如果在该动态链接库过程中的某个字符不符合动态链接库的命名约定时,也可以使用Alias。
❑ aliasname:可选的。动态链接库或代码资源中的过程名。如果首字符不是数字符号(#),则aliasname是动态链接库中该过程的入口处的名称。如果首字符是(#),则随后的字符必须指定该过程的入口处的顺序号。
❑ arglist:可选的。代表在调用该过程时需要传递的参数的变量表。
❑ type:可选的。Function过程返回值的数据类型,可以是Byte、布尔、Integer、Long、Currency、Single、Double、Decimal(目前尚不支持)、Date、String(只支持变长)、Variant、用户自定义类型或对象类型。
4.4.2 数据赋值——SET
SET命令即可用于对局部变量进行赋值,也可用于设定用户执行SQL命令时SQL Server的处理选项设定。当SET用于给局部变量赋值时语法如下:
SET {@local_variable = expression}
当用于设定用户执行SQL命令时可能有以下几种设定方式:
❑ SET设定为ON选项开关打开。
❑ SET设定为OFF选项开关关闭。
❑ SET设定为 =设定选项为具体值。
SELECT语句同样可以用于给变量赋值。其语法如下:
SELECT {@LOCAL_VARIABLE = expression}
SELECT命令可以一次给一个或者多个变量赋值。当expression为列名时,SELECT命令可利用其查询功能以此返回多个值,但是变量保存的是其最后一个值,如果SELECT没有返回值,则变量值为原来的值。
4.4.3 数据输出——PRINT
PRINT输出时的语法如下:
PRINT @local_variable| @@FUNCTION
PRINT命令向客户端返回一个用户自定义的信息,即显示一个字符串的局部变量或者全局变量。如果变量不是字符串必须先用数据列席转换函数CONVERT()转换为字符串。
SELECT同样可以完成数据输出任务,其语法如下:
SELECT @local_variable | @@FUNNCTION | string_expression
具体应用已在局部变量处详细介绍。
4.5 循环控制语句
SQL语句按从上至下的顺序执行,但是在很多时候并不是我们所希望的。Transact-SQL提供了用于编写过程性代码的语法结构,使在程序执行时按照自己的意愿改变程序执行的顺序。T-SQL可用来进行顺序、分支、循环、存储过程、批处理、语句块等程序设计,编写结构化的模块代码。下面介绍主要的流程控制语句。
4.5.1 语句块BEGIN…END
使用BEGIN和END关键字来创建SQL语句块。BEGIN和END块间的语句按单个语句块处理,按一个单元执行。BEGIN和END通常用于定义包含其他流程控制语句(如IF、WHILE及CASE)的语句块。语法如下:
BEGIN {sql_statement | statement_block} END
BEGIN…END经常在条件语句如IF…ELSE或重复执行语句WHILE中。在通常情况下,IF、WHILE等语句内只允许包含一条语句,但是在实际程序中,这显然不能满足复杂的程序设计要求。BEGIN…END弥补了这个不足。
【例4-25】BEGIN…END的使用。
DECLARE @num int SELECT @num = 0 While @num <10 BEGIN SELECT @num = @num+1 SELECT @num END
4.5.2 GOTO语句
GOTO语句将执行控制从代码中的一个位置转移至用户定义标签后的另一个位置。GOTO语句和标号可以用在存储过程、批处理或者语句块中,标号名必须遵守T-SQL命名规则。在一般情况下,GOTO语句常用在WHILE语句和IF语句中。
使用GOTO语句,首先定义一个标号,其语法如下:
标号:
然后使用GOTO语句转移到所定义的标签处,语法如下:
GOTO标签
【例4-26】GOTO语句的使用。
BEGIN SELECT stu_id FROM student GOTO SKIP SELECT * FROM student SKIP: PRINT ‘The second SELECT did not get executed’ END
由于GOTO语句可以转移到程序任意标号位置,不符合结构化程序设计只采用顺序、分支、循环3种结构的思想,所以在实际编程中并不建议应用。
4.5.3 IF…ELSE语句
如果需要在执行一组语句前先测试条件,则会在代码中同时存在几种情况。因此,IF…ELSE语句可以用来求布尔表达式的值。IF语句提出可能的情况,接着基于这些情况会有相应的执行语句。ELSE关键字便于IF返回FALSE时执行其他语句。其语法如下:
IF boolean_expression {sql_statement | statement_block} [ELSE IF boolean_expression {sql_statement | statement_block}] [ELSE {sql_statement | statement_block}]
其中boolean_expression可以是各种表达式的组合,但表达式必须返回逻辑值真或假。ELSE部分只是对IF部分的一个补充。IF…ELSE用来判断当某条件成立时执行某段程序,当条件不成立时执行另一段程序。如果IF…ELSE不和BEGIN…END联合使用,IF或ELSE内只能执行单条语句。
【例4-27】IF…ELSE语句的嵌套使用。
DECLAER @x int,@y int ,@z int SELECT @x = 2, @y = 5,@ z = 4 IF @x > @y PRINT 'x>y' ELSE IF @ y> @z PRINT 'y>z' ELSE PRINT 'z>y'
4.5.4 CASE语句
CASE语句用于多条件分支选择。虽然IF…ELSE在某些时候同样可以完成CASE语句所要实现的功能,但是使用CASE语句可以更加简化SQL表达式。CASE关键字使你可根据表达式的真假来确定是否返回某个值。可在允许使用表达式的任何位置使用这一关键字。具体语法如下:
CASE expression WHEN expression1 THEN expression1 [[WHEN expression2 THEN expression2] […]] [ELSE expressionN] END
其执行过程是:将CASE后表达式的值与各WHEN子句的表达式值比较,如果相等,则返回THEN后面的表达式,然后跳出CASE语句,否则返回ELSE后面的表达式。
【例4-28】使用CASE语句对考试成绩进行评价。
select score, case when score > 90 then '非常优秀' when score > 80 then '优秀' when score > 70 then '良好' when score > 60 then '及格' else '不及格' end from score
运行代码,结果如图4.19所示。
图4.19 使用CASE语句对考试成绩进行评价
4.5.5 WHILE循环语句
在WHILE语句中设置重复执行SQL语句或语句块的条件。只要指定的条件为真,就重复执行语句。在很多时候,可以使用BREAK和CONTINUE关键字在循环内部控制WHILE循环中语句的执行。具体语法如下:
WHILE Boolean_expression { sql_statement | statement_block } [ BREAK ] { sql_statement | statement_block } [ CONTINUE ]
各参数说明如下:
❑ Boolean_expression:返回TRUE或FALSE的表达式。如果布尔表达式中含有SELECT语句,则必须用括号将SELECT语句括起来。
❑ {sql_statement → statement_block}:Transact-SQL语句或用语句块定义的语句分组。若要定义语句块,请使用控制流关键字BEGIN和END。
❑ BREAK:导致从最内层的WHILE循环中退出。将执行出现在END关键字(循环结束的标识)后面的任何语句,即退出当前循环。
❑ CONTINUE:使WHILE循环重新开始执行,忽略CONTINUE关键字后面的任何语句,即重新执行此循环。
Tips
WHILE语句可以嵌套使用BEGIN…END语句。
【例4-29】循环语句及嵌套程序的使用。
declare @i int set @i =5 while @i > -1 begin print @i set @i =@i -1 if @i =1 break end
运行结果如下:
5 4 3 2
4.5.6 WAITFOR语句
很多事情,可能不愿意或无法马上就做,不过也不愿意一直等到适当的时间再去做需要的事情。SQL中提供了WAITFOR语句,它用于暂时停止执行SQL语句、语句块或者存储过程等,直到所设定的时间已过或者已到才继续执行。具体语法如下:
WAITFOR DELAY <'time'> | TIME <'time'>
WAITFOR语句会等你输入指定参数。你可以指定某件事的确切发生时间,也可以指定要等待的时间。参数说明如下:
1.DELAY参数
DELAY参数选项指定要等待的时间。它不能被指定为多日,只能指定为小时、分钟和秒。所允许的最大延迟时间是24小时。
例如:
--直到11:00后程序继续执行 WAITFOR TIME '11:00:00'
2.TIME参数
TIME参数选项指定等待到一天中的某个特定时刻。同样,我们不能指定其他的日期类型,只能用24时制的时间。同时,最大延迟时间为一天。例如:
WAITFOR DELAY '01:00'
这将运行WAITFOR前的任何代码,随后执行WAITFOR语句,再停止一小时,一小时之后,会继续执行下一行语句。
Tips
在上述程序运行后将长时间挂起,可以按“Alt+Break”组合键来停止程序的执行。
4.5.7 RETURN语句
RETURN命令用于结束当前程序的执行,返回到上一个调用它的程序或其他程序,其语法格式如下:
RETURN 整数值或变量
RETURN语句要指定返回值。如果没有指定返回值,SQL Server系统会根据程序执行的结果返回一个内定值,返回值含义如表4.2所示。
表4.2 RETURN语句的返回值
Tips
如果运行过程中产生了多个错误,SQL SERVER系统将返回绝对值最大的数值。如果此时定义了返回值,则返回用户定义的值。RETURN语句不能返回null。
4.6 批处理语句
批处理:从客户机传递到服务器上的一组完整的数据和SQL指令(可以是一条也可以包含多条SQL指令)组成一个批处理。
❑ 一个批处理中只要存在一处语法错误,整个批处理都无法通过编译。
❑ 批处理中可以包含多个存储过程,但除第一个存储过程外在其他存储过程前面都必须使用Exec关键字。
❑ 某些特殊的SQL指令不能和别的SQL指令共存在一个批处理中。如Create Table命令、Create View命令等,这些指令只能独自存在于一个单独的存储过程中。
❑ 所有的批处理命令使用GO作为结束的标志。当编译器读到GO的时候就把GO前面的所有语句当做一个批处理,然后打包成一个数据包发给服务器。
❑ GO本身并不是Transact-SQL语句的组成部分,只是一个用于表示批处理结束的前端指令。
❑ 在有情况下,如果SQL指令中存在一些错误,编译的时候无法识别则在执行的时候就会出错,这样在执行完一部分批处理操作后会产生一些无用的垃圾数据。
建立批处理需注意以下内容:
❑ create default、create rule、create trigger和create view等语句在同一个批处理中只能提交一个。
❑ 不能在删除一个对象之后,在同一批处理中再次引用这个对象。
❑ 不能在把规则和默认值绑定到表字段或者自定义字段后,立即在同一批处理中使用它们。
❑ 不能在定义一个check约束之后,立即在同一个批处理中使用。
❑ 不能在修改表中一个字段名之后,立即在同一个批处理中引用这个新字段。
❑ 使用set语句设置的某些set选项不能应用于同一个批处理中的查询。
❑ 若在批处理中第一个语句是执行某个存储过程的execute语句,则execute关键字可以省略。若该语句不是第一个语句,则必须写上。
【例4-30】使用批处理查询student表中所有学生信息。
--打开数据库stu USE STU GO --查询所有学生信息 SELECT * FROM student
运行代码,结果如图4.20所示。
图4.20 批处理的应用
GO此处使用了两个批处理。第一个批处理完成打开数据库STU的任务,第二个批处理完成学生信息查询的任务。每个语句都单独作为一个批处理提交服务器,进行编译并生成执行计划。
4.7 小结
SQL语句是SQL Server的核心,是进行SQL Server 2005数据库编程的基础。本章对数据定义语句(DDL)、数据操作语句(DML)、数据控制语句(DCL)等进行介绍,并且对一些基本语句,如DECLARE语句、SET语句、PRINT等进行简要介绍。接着介绍了常用循环控制语句如BEGIN…END、GOTO、IF…ELSE、CASE等的应用,最后介绍了在实际编程中常使用的批处理语句,使读者了解SQL语句的基本分类,准确掌握基本流程控制语句。
4.8 习题
1.T-SQL语言包括哪些具体内容。
为管理岗位业务培训信息,建立3个表。
❑ S (S#,SN,SD,SA):S#,SN,SD,SA分别代表学号、学员姓名、所属单位、学员年龄。
❑ C (C#,CN ):C#、CN分别代表课程编号、课程名称。
❑ SC ( S#,C#,G ):S#、C#、G分别代表学号、所选修的课程编号、学习成绩。
2.根据上面内容,使用标准SQL嵌套语句查询选修课程名称为‘税收基础’的学员学号和姓名。
3.使用标准SQL嵌套语句查询选修课程编号为‘C2’的学员姓名和所属单位。
4.查询选修了课程的学员人数。
5.使用标准SQL嵌套语句查询选修全部课程的学员姓名和所属单位。