Top Banner
第9第 Transact-SQL 第第第
144

第9章 transact sql程序设计

Nov 02, 2014

Download

Documents

hanmo1988

 
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: 第9章   transact sql程序设计

第 9 章 Transact-SQL 程序设计

Page 2: 第9章   transact sql程序设计

本章内容

9.1 数据与表达式9.2 函 数9.3 程序控制流语句9.4 游标管理与应用

Page 3: 第9章   transact sql程序设计

9.1 数据与表达式

9.1.1 用户定义数据类型9.1.2 常量与变量9.1.3 运算符与表达式

Page 4: 第9章   transact sql程序设计

9.1 数据与表达式

9.1.1 用户定义数据类型

1 .使用系统存储过程来创建用户定义数据类型 , 命令格式如下:sp_addtype [@typename=] type,

[@phystype = ] system_data_type

[, [ @nulltype = ] 'null_type' ]

[, [ @owner = ] 'owner_name' ]

Page 5: 第9章   transact sql程序设计

9.1.1 用户定义数据类型

例如,为 Sales 数据库创建—个不允许为 NULL 值的 test_add 用户定义数据类型。

USE Sales

GO

EXEC sp_addtype test_add,'Varchar(10)','NOT NULL'

GO 此后, test_add 可用为数据列或变量的数

据类型。

Page 6: 第9章   transact sql程序设计

9.1.1 用户定义数据类型

2 .使用企业管理器创建用户定义数据类型

在企业管理器中,为 Sales 数据库创建—个不允许 NULL值的 test_add 用户定义数据类型,操作步骤如下。(1) 选择 Sales 数据库。(2) 在左窗格中选择“用户定义的数据类型”项,单击鼠标右键,在

出现的快捷菜单中选择“新建用户定义数据类型”命令。(3) 在“用户定义的数据类型属性”对话框中的文本框内输入 test_ad

d 。(4) 在“数据类型”下拉列表框中,选择 char 。(5) 在“长度”文本框中输入 10 。(6) 选中“允许 NULL 值”复选框。(7) 单击“确定”按钮完成创建用户自定义数据类型。

Page 7: 第9章   transact sql程序设计

9.1 数据与表达式

9.1.2 常量与变量 在程序运行中保持常值的数据,即程序本身

不能改变其值的数据,称为常量,在程序中经常直接使用文字符号表示。

相应地,在程序运行过程中可以改变其值的数据,称为变量。

Page 8: 第9章   transact sql程序设计

9.1.2 常量与变量

1 .常量 常量是表示特定数据值的符号,其格式取决于其

数据类型(1) 字符串和二进制常量

字符串常量括在单引号内并包含字母数字字符 (a-z 、A-Z 和 0-9) 以及特殊字符,如感叹号 (!) 、 at 符 (@)和数字号 (#) 。

例如:‘ Cincinnati’ 、 ‘ Process X is 50% complete.’为字符串常量。

二进制常量具有前辍 0x 并且是十六进制数字字符串,它们不使用引号。例如 0xAE 、 0x12Ef 、 0x69048AEFDD010E 、 0x( 空串 ) 为二进制常量。

Page 9: 第9章   transact sql程序设计

(2) 日期 / 时间常量 datetime 常量使用特定格式的字符日期值表示,用单引

号括起来。 输入时,可以使用“ /” 、“ .” 、“ -” 作日期 / 时间常

量的分隔符。

输入格式 datetime值 Smalldatetime值Sep 3, 2005 1:34:34.122 2005-09-03 01:34:34.123 2005-09-03 01:35:00

9/3/2005 1PM 2005-09-03 13:00:00.000 2005-09-03 13:00:00

9.3.2005 13:00 2005-09-03 13:00:00.000 2005-09-03 13:00:00

13:25:19 1900-01-01 13:25:19.000 1900-01-01 13:25:00

9/3/2005 2005-09-03 00:00:00.000 2005-09-03 00:00:00

9.1.2 常量与变量

Page 10: 第9章   transact sql程序设计

(3) 数值常量① 整型常量 --- 由没有用引号括起来且不含小数点的一串数

字表示。例如, 1894 、 2 为整型常量。② 浮点常量 --- 采用科学记数法表示,例如, 101.5E5 、 0.5

E-2 为浮点常量。③ 精确数值常量 --- 由没有用引号括起来且包含小数点的一

串数字表示。例如, 1894.1204 、 2.0 为精确数值常量。④ 货币常量 --- 以“ $” 为前缀的一个整型或实型常量数据,

不使用引号。例如, $12.5 、 $542023.14 为货币常量。⑤uniqueidentifier 常量 --- 表示全局惟一标识符 GUID 值的

字符串。可以使用字符或二进制字符串格式指定。

9.1.2 常量与变量

Page 11: 第9章   transact sql程序设计

(4) 逻辑数据常量 逻辑数据常量使用数字 0 或 1 表示,并且

不使用引号。非 0 的数字当作 1 处理。(5) 空值 在数据列定义之后,还需确定该列是否允

许空值 (NULL) 。允许空值意味着用户在向表中插入数据时可以忽略该列值。空值可以表示整型、实型、字符型数据。

9.1.2 常量与变量

Page 12: 第9章   transact sql程序设计

变量用于临时存放数据,变量中的数据随着程序的运行而变化,变量有名字与数据类型两个属性。

变量的命名使用常规标识符,即以字母、下划线 (_) 、 at 符号 (@) 、数字符号 (#) 开头,后续字母、数字、 at 符号、美元符号 ($) 、下划线的字符序列。不允许嵌入空格或其他特殊字符。

2 .变量9.1.2 常量与变量

Page 13: 第9章   transact sql程序设计

全局变量由系统定义并维护,通过在名称前面加“ @@” 符号

局部变量的首字母为单个“ @” 。

全局变量和局部变量

Page 14: 第9章   transact sql程序设计

(1) 局部变量 局部变量使用 DECLARE 语句定义

DECLARE {@local_variable data_type }[,...n] 变量名最大长度为 30 个字符。一条 DECL

ARE 语句可以定义多个变量,各变量之间使用逗号隔开。

例如DECLARE @name varchar(30),@type int

9.1.2 常量与变量

Page 15: 第9章   transact sql程序设计

局部变量的赋值局部变量用 select 、 print 显示,用 select 、 update 、 set

赋值① 用 SELECT 为局部变量赋值

SELECT @variable_name=expression[ , … n]

FROM …

WHERE …

例如 DECLARE @int_var int SELECT @int_var =12 /* 给 @int_var 赋值 */ SELECT @int_var /* 将 @int_var 的值输出到屏幕上 */

Page 16: 第9章   transact sql程序设计

在一条语句中可以同时对几个变量进行赋值

例如 DECLARE @LastName char(8),@Firstname char(8),@

BirthDate datetime SELECT @LastName='Smith',@Firstname='David',@

BirthDate='1985-2-20' SELECT @LastName,@Firstname,@BirthDate

局部变量没有被赋值前,其值是 NULL ,若要在程序中引用它,必须先赋值。

9.1.2 常量与变量

Page 17: 第9章   transact sql程序设计

例 9-1 使用 SELECT 语句从 customer 表中检索出顾客编号为“ C0002” 的行,再将顾客的名字赋给变量 @customer 。DECLARE @customer varchar(40),@curdate datetime

SELECT @customer=customer_name,@curdate=getdate()

FROM customer

WHERE customer_id='C0002'

9.1.2 常量与变量

Page 18: 第9章   transact sql程序设计

②利用 UPDATE 为局部变量赋值

例 9-2 将 sell_order 表中的 transporter_id 列值为“ T001” 、 goods_id 列值为“ G00003” 的 order_num 列的值赋给局部变量 @order_num 。DECLARE @order_num float

UPDATE sell_order

SET @order_num=order_num*2

WHERE transporter_id='T001' AND goods_id='G00003'

9.1.2 常量与变量

Page 19: 第9章   transact sql程序设计

③ 用 SET 给局部变量赋值 SET 语句格式为:

SET {@local_variable=expression} 使用 SET初始化变量的方法与 SELECT 语句相同,但一个 SET 语句只能为一个变量赋值。

例 9-3 计算 employee 表的记录数并赋值给局部变量 @rows 。DECLARE @rows intSET @rows=(SELECT COUNT(*) FROM employee)SELECT @rows

9.1.2 常量与变量

Page 20: 第9章   transact sql程序设计

例 声明一个 datetime 类型的局部变量。 DECLARE @date_var datetime例 声明两个局部变量。 DECLARE @var1 int , @var2 money例 用 SET 语句和 SELECT 语句为局部变量赋值。 DECLARE @var1 datetime,@var2 char(10) SET @var1 = getdate() SELECT @var2 = convert(char(10),@var1,102)例 用 SET 语句将查询结果赋给局部变量并用 SELECT 语句

显示局部变量的值。 declare @date_var datetime set @date_var=(select min(birthday) from s) select @date_var as min_birthday

Page 21: 第9章   transact sql程序设计

(2) 全局变量 全局变量:常被服务器用来跟踪服务器范围和特定会话期间的信息,不能显式地被赋值或声明。

全局变量不能由用户定义,也不能被应用程序用来在处理器之间交叉传递信息。

9.1.2 常量与变量

Page 22: 第9章   transact sql程序设计

①@@rowcount

@@rowcount 存储前一条命令影响到的记录总数,除了 DECLARE 语句之外,其他任何语句都可以影响@@rowcount 的值。

例如DECLARE @rows int

SELECT @rows=@@rowcount

9.1.2 常量与变量

Page 23: 第9章   transact sql程序设计

② @@error 如果@@error 为非 0 值,则表明执行过程中产生了错误,

此时应当在程序中采取相应的措施加以处理。 @@error 的值与 @@rowcount 一样,会随着每一条 SQL

Server 语句的变化而改变。例 9-4 使服务器产生服务,并显示错误号。

raiserror('miscellaneous error message',16,1) /*产生一个错误 */if @@error<>0SELECT @@error as 'last error'

运行结果:服务器 : 消息 50000 ,级别 16 ,状态 1 ,行 1miscellaneous error messagelast error0

9.1.2 常量与变量

Page 24: 第9章   transact sql程序设计

例 9-5 捕捉例 9-4 中服务器产生的错误号,并显示出来。

DECLARE @my_error intRAISERROR('miscellaneous error message',16,1)SELECT @my_error=@@errorIF @my_error<>0 SELECT @my_error as 'last error'

运行结果:服务器 : 消息 50000 ,级别 16 ,状态 1 ,行 2miscellaneous error messagelast error50000

9.1.2 常量与变量

Page 25: 第9章   transact sql程序设计

③@@trancount @@trancount 记录当前的事务数量,当某个事务当前

并没有结束会话过程时, @@trancount 的值大于 0 。 ④@@version @@version 的值代表服务器的当前版本和当前操作系

统版本,是 SQL Server 中一项较实用的技术支持,通常对识别网络中某个未命名的服务器时非常有用。

⑤@@spid @@spid返回当前用户进程的服务器进程 ID ,可以用

来识别 sp_who 输出中的当前用户进程。

Page 26: 第9章   transact sql程序设计

例 9-6 使用 @@spid 返回当前用户进程的 ID 。

SELECT @@spid as 'ID',SYSTEM_USER AS 'Login Name',USER AS 'User Name'

运行结果:ID Login Name User Name

52 sa dbo

9.1.2 常量与变量

Page 27: 第9章   transact sql程序设计

9.1 数据与表达式

9.1.3 运算符与表达式 运算符用来执行数据列之间的数学运算或比较操作。

表达式是符号与运算符的组合。简单的表达式可以是一个常量、变量、列

或函数,复杂表达式是由运算符连接一个或多个简单表达式。

Page 28: 第9章   transact sql程序设计

9.1.3 运算符与表达式

1. 算术运算符与表达式

算术运算符用于数值型列或变量间的算术运算。算术运算符包括加 (+) 、减 (-) 、乘 (*) 、除 (/) 和取模 (%) 运算等。

例 9-9 使用“ +” 将 goods 表中高于 9000 的商品价格增加 15 元:SELECT goods_name,unit_price,(unit_price+15) AS now

price

FROM goods

WHERE unit_price>9000 运行结果如图所示。

Page 29: 第9章   transact sql程序设计

9.1.3 运算符与表达式

2. 位运算符与表达式

位运算符用以对数据进行按位与 (& ) 、或 (|) 、异或 (^) 、求反 (~)等运算。 & 运算只有当两个表达式中的两个位值都为 1 时,结果中的位才被设置为 1 ,否则结果中的位被设置为 0 。

| 运算时,如果在两个表达式的任一位为 1 或者两个位均为 1 ,那么结果的对应位被设置为 1;如果表达式中的两个位都不为 1 ,则结果中该位的值被设置为 0 。

^ 运算时,如果在两个表达式中,只有一位的值为 1 ,则结果中位的值被设置为 1;如果两个位的值都为 0 或者都为 1 ,则结果中该位的值被清除为 0 。

Page 30: 第9章   transact sql程序设计

9.1.3 运算符与表达式

例如, 170 与 75 进行 & 运算先将 170 和 75转换为二进制数 0000 0000 1

010 1010 和 0000 0000 0100 1011 ,再进行& 运算的结果是 0000 0000 0000 1010 ,即十进制数 10 。

同样,表达式 5^2 , ~1 , 5|2 的运算结果为: 7 , 0 , 7 。

Page 31: 第9章   transact sql程序设计

9.1.3 运算符与表达式

3. 比较运算符与表达式 比较运算符用来比较两个表达式的值是否相同,

可用于字符、数字或日期数据。 SQL Server 中的比较运算符有大于 (>) 、小于 (<) 、

大于等于 (>=) 、小于等于 (<=) 和不等于 (!=)等,比较运算返回布尔值,通常出现在条件表达式中。

比较运算符的结果为布尔数据类型,其值为 TRUE 、 FALSE 及 UNKNOWN 。

例如,表达式 2=3 的运算结果为 FALSE 。

Page 32: 第9章   transact sql程序设计

9.1.3 运算符与表达式

4. 逻辑运算符与表达式 逻辑运算符与 (AND) 、或 (OR) 、非 (NO

T)等,用于对某个条件进行测试,以获得其真实情况。

逻辑运算符和比较运算符一样,返回 TRUE 或 FALSE 的布尔数据值。

Page 33: 第9章   transact sql程序设计

9.1.3 运算符与表达式

表 9-5 逻辑运算符运算符 含 义

AND 如果两个布尔表达式都为 TRUE,那么结果为 TRUE。OR 如果两个布尔表达式中的一个为 TRUE,那么结果就为 TRUE。NOT 对任何其他布尔运算符的值取反。LIKE 如果操作数与一种模式相匹配,那么值为 TRUE。IN 如果操作数等于表达式列表中的一个,那么值为 TRUE。ALL 如果一系列的比较都为 TRUE,那么值为 TRUE。ANY 如果一系列的比较中任何一个为 TRUE,那么值为 TRUE。BETWEEN 如果操作数在某个范围之内,那么值为 TRUE。EXISTS 如果子查询包含一些行,那么值为 TRUE。

Page 34: 第9章   transact sql程序设计

9.1.3 运算符与表达式

逻辑运算符通常和比较运算一起构成更为复杂的表达式。逻辑运算符的操作数都只能是布尔型数据。

例如,在表 employee 中查找 1973年以前与 1980年以后出生的男员工的表达式为:(year(birth_date)<1973 OR year(birth_date)>198

0) AND sex='男 '

Page 35: 第9章   transact sql程序设计

9.1.3 运算符与表达式

LIKE 运算符 确定给定的字符串是否与指定的模式匹配,通常只限于字符数据类型。 LIKE 的通配符如下表运算符 描 述 示 例

% 包含零个或多个字符的任意字符串。

address LIKE '%公司%' 将查找地址任意位置包含公司的所有职员。

_ 下划线,对应任何单个字符。 employee_name LIKE '_海燕 ' 将查找以“ ”海燕 结尾的所有 6个字符的名字。

[ ] 指定范围 ([a-f ])或集合 ([abcdef ])中的任何单个字符。

employee_name LIKE '[张李王 ]海燕 ' 将查找张海燕、李海燕、王海燕等。

[^] 不属于指定范围 ([a-f ])或集合([abcdef ])的任何单个字符。

employee_name LIKE '[^张李 ]海燕 ' 将查找不姓张、李的名为海燕的职员。

Page 36: 第9章   transact sql程序设计

9.1.3 运算符与表达式

例如 , 查找所有姓“钱”的员工及住址SELECT employee_name, address

FROM employee

WHERE employee_name LIKE '钱%'

Page 37: 第9章   transact sql程序设计

9.1.3 运算符与表达式

4 .连接运算符与表达式

连接运算符 (+) 用于两个字符串数据的连接,通常也称为字符串运算符。

在 SQL Server 中,对字符串的其他操作通过字符串函数进行。字符串连接运算符的操作数类型有 char 、 varchar 和 text等。

例如,‘Dr.’+‘Computer’ 的运算结果 :'Dr. Computer'

Page 38: 第9章   transact sql程序设计

9.1.3 运算符与表达式

5 .运算符的优先级别 SQL Server 中各种运算符的优先顺序如下:

( ) → ~ → ^ → & → | → * 、 / 、 % → + 、 - → NOT → AND → OR

排在前面的运算符的优先级高于其后的运算符。在一个表达式中,先计算优先级较高的运算,后计算优先级低的运算,相同优先级的运算按自左向右的顺序依次进行。

Page 39: 第9章   transact sql程序设计

9.2 函 数9.2.1 常用函数9.2.2 用户定义函数

Page 40: 第9章   transact sql程序设计

9.2 函 数

9.2.1 常用函数 函数是—组编译好的 Transact-SQL 语句,它们可以带一个或一组数值做参数,也可不带参数,它返回一个数值、数值集合,或执行一些操作。

函数能够重复执行一些操作,从而避免不断重写代码。 SQL Server 2000支持两种函数类型:

(1) 内置函数 : 是一组预定义的函数,是 Transact-SQL 语言的一部分,按 Transact-SQL参考中定义的方式运行且不能修改。

(2) 用户定义函数 : 由用户定义的 Transact-SQL 函数。它将频繁执行的功能语句块封装到一个命名实体中,该实体可以由 Transact-SQL 语句调用。

Page 41: 第9章   transact sql程序设计

9.2.1 常用函数

1 .字符串函数 字符串函数用来实现对字符型数据的转换、查找、分析等操作,通常用做字符串表达式的一部分。表 9-7 中列出了 SQL Server的常用字符串函数。

Page 42: 第9章   transact sql程序设计

9.2.1 常用函数

(1) 使用 datalength 和 Len 函数

datalength 函数主要用于判断可变长字符串的长度,对于定长字符串将返回该列的长度。要得到字符串的真实长度,通常需要使用 rtrim 函数截去字符串尾部的空格。

Len 函数可以获取字符串的字符个数,而不是字节数,也不包含尾随空格。

Page 43: 第9章   transact sql程序设计

9.2.1 常用函数

例 9-10 从表 department 中读取 manger 列的各记录的实际长度。

SELECT Datalength(rtrim(manger)) AS 'DATALENGTH',

Len(rtrim(manger)) AS 'LEN'FROM department

运行结果如下:DATALENGTH LEN4 26 36 36 3

Page 44: 第9章   transact sql程序设计

9.2.1 常用函数

(2) 使用 Soundex 函数 soundex 函数将 char_expr转换为 4 个字符的声音码,其

中第一个码为原字符串的第一个字符,第 2~4 个字符为数字,是该字符串的声音字母所对应的数字,但忽略了除首字母外的串中的所有元音。

Soundex 函数可用来查找声音相似的字符串,但它对数字和汉字均只返回 0 值。

例如SELECT soundex('1'),soundex('a'), soundex(' 计算机 '), soundex('ab

c'), soundex ('abcd'), soundex('a12c'), soundex('a 数字 ')返回值为:0000 A000 0000 A120 A120 A000 A000

Page 45: 第9章   transact sql程序设计

9.2.1 常用函数

(4) 使用 Charindex 函数实现串内搜索 charindex 函数主要用于在串内找出与指定串匹配

的串,如果找到的话, charindex 函数返回第一个匹配的位置。格式:Charindex(expr1, expr2[, start_location]) expr1 是待查找的字符串 expr2 是用来搜索 expr1子串的字符表达式, start_location 是在 expr2 中查找 expr1 的开始位置,

如果此值省略、为负或为 0 ,均从起始位置开始查找。

Page 46: 第9章   transact sql程序设计

9.2.1 常用函数

例如

SELECT charindex(',', 'red,white,blue')

该查询确定了字符串 'red,white,blue' 中第一个逗号的位置。

Page 47: 第9章   transact sql程序设计

9.2.1 常用函数

(5) 使用 Patindex 函数 patindex 函数返回在指定表达式中模式第一次出

现的起始位置,如果模式没有则返回 0 。格式:Patindex('%pattern%', expression) pattern 是字符串, % 字符必须出现在模式的开头和结尾。 expression 通常是搜索指定子串的表达式或列。

例如:SELECT patindex('%abc%','abc123'), patindex('123','abc123') 子串“ abc” 和“ 123” 在字符串“ abc123” 中出现的起始位置分别为: 1 和 0 。因为子串“ 123” 不是以 % 开头和结尾。

Page 48: 第9章   transact sql程序设计

9.2.1 常用函数

2 .数学函数 数学函数用来实现各种数学运算,如指数

运算、对数运算、三角运算等,其操作数为数值型数据,如 int 、 float 、 real 、 money等

表 9-8 列出了 SQL Server 的数学函数。

Page 49: 第9章   transact sql程序设计

9.2.1 常用函数

例 9-11 在同一表达式中使用 sin 、 atan 、 rand 、 pi 、 sign 函数。

SELECT sin(23.45), atan(1.234), rand(), pi(), sign(-2.34)

运行结果如下:-0.99374071017265964 0.88976244895918932 0.1975661765616786

3.1415926535897931 -1.00

Page 50: 第9章   transact sql程序设计

9.2.1 常用函数

例 9-12 用 ceiling 和 floor 函数返回大于或等于指定值的最小整数值和小于或等于指定值的最大整数值。

SELECT ceiling(123),floor(321), ceiling(12.3), ceiling(-32.1),floor(-32.1)

运行结果如下:123 321 13 -32 -33

Page 51: 第9章   transact sql程序设计

9.2.1 常用函数

SELECT round(12.34512,3), round(12.34567,3), round(12.345,-2), round(54.321,-2)

运行结果如下:12.34500 12.34600 .000 100.000

Round(numeric_expr, int_expr) 的 int_expr 为负数时,将小数点左边第 int_expr位四舍五入。

例 9-13 round 函数的使用。

Page 52: 第9章   transact sql程序设计

9.2.1 常用函数

3 .日期函数 日期函数用来操作 datetime 和 smalldateti

me 类型的数据,执行算术运算。与其他函数一样,可以在 SELECT 语句和 WHERE子句以及表达式中使用日期函数。

Page 53: 第9章   transact sql程序设计

9.2.1 常用函数

表 9-9 SQL Server的日期函数函数名称及格式 描 述

Getdate() 返回当前系统的日期和时间Datename(datepart, date_expr) 以字符串形式返回 date_expr中的指定部分,如果合适的

话还将其转换为名称 (如 June)

Datepart(datepart, date_expr) 以整数形式返回 date_expr中的 datepart指定部分Datediff(datepart,date_expr1,date

_expr2)以 datepart指定的方式,返回 date_expr2与 date_expr1之差

Dateadd(datepart, number, date_expr)

返回以 datepart指定方式表示的 date_expr加上 number以后的日期

Day(date_expr) 返回 date_expr中的日期值Month(date_expr) 返回 date_expr中的月份值Year(date_expr) 返回 date_expr中的年份值

Page 54: 第9章   transact sql程序设计

9.2.1 常用函数

表 9-10 SQL Server 的日期部分日期部分 写 法 取值范围

Year yy 1753~9999

Quarter qq 1~4

Month mm 1~12

Dayofyear dy 1~366

Day dd 1~31

Week wk 1~54

Weekday dw 1~7(Mon~Sun)

Hour hh 0~23

Minute mi 0~59

Second ss 0~59

Millisecond ms 0~999

Page 55: 第9章   transact sql程序设计

9.2.1 常用函数

例 9-14 使用 datediff 函数来确定货物是否按时送给客户。

SELECT goods_id,datediff(dd,send_date,arrival_date)

FROM purchase_order

为了从 datediff 中得到一个正值,应注意把较早的日期放在前面

Page 56: 第9章   transact sql程序设计

9.2.1 常用函数

例 9-15 使用 datename 函数返回员工的出生日期的月份 (mm) 名称。

SELECT employee_name,datename(mm,birth_date)

FROM employee

运行结果如下:钱达理 December

东方牧 April

郭文斌 March

肖海燕 July

张明华 August

Page 57: 第9章   transact sql程序设计

9.2.1 常用函数

4 .系统函数 系统函数用于获取有关计算机系统、用户、

数据库和数据库对象的信息。与其他函数一样,可以在 SELECT 和 WHERE子句以及表达式中使用系统函数。

表 9-11 列出了 SQL Server 的系统函数。

Page 58: 第9章   transact sql程序设计

9.2.1 常用函数

例 9-16 使用 object_name 函数返回已知 ID号的对象名。

SELECT object_name(469576711) 运行结果如下:

Employee

Page 59: 第9章   transact sql程序设计

9.2.1 常用函数

例 9-17 利用 object_id 函数,根据表名返回该表的 ID 号。

SELECT name FROM sysindexes

WHERE id=object_id('customer') 运行结果如下:

name

customer

_WA_Sys_customer_id_75D7831F

Page 60: 第9章   transact sql程序设计

9.2 函 数

9.2.2 用户定义函数根据函数返回值形式的不同将用户定义函数分为 3种类型。(1) 标量函数

标量函数返回一个确定类型的标量值,其函数值类型为 SQL Server 的系统数据类型(除 text 、 ntext 、 image 、 cursor 、 timestamp 、 table 类型外)。函数体语句定义在 BEGIN…END 语句内。

(2) 内嵌表值函数内嵌表值函数返回的函数值为一个表。内嵌表值函数的函数

体不使用 BEGIN…END 语句,其返回的表是 RETURN子句中的 SELECT 命令查询的结果集,其功能相当于一个参数化的视图。

(3) 多语句表值函数多语句表值函数可以看作标量函数和内嵌表值函数的结合体。

其函数值也是一个表,但函数体也用 BEGIN…END 语句定义,返回值的表中的数据由函数体中的语句插入。

Page 61: 第9章   transact sql程序设计

9.2.2 用户定义函数

1. 创建用户定义函数(1) 使用 CREATE FUNCTION 创建用户定义函数 标量函数的语法格式:

CREATE FUNCTION [owner_name.] function_name( [{ @parameter_name [AS] scalar_parameter_data_type[=default ] }

[ ,...n ] ] ) RETURNS scalar_return_data_type[ WITH < function_option> [ [,] ...n] ] [ AS ]BEGIN function_body RETURN scalar_expressionEND注: function_option , ENCRYPTION :加密函数,SCHEMABINDING :不能更改或删除相关的数据库对象

Page 62: 第9章   transact sql程序设计

9.2.2 用户定义函数

例 9-18 创建一个用户定义函数 DatetoQuarter ,将输入的日期数据转换为该日期对应的季度值。如输入 '2006-8-5' ,返回 '3Q2006' ,表示 2006 年 3 季度。CREATE FUNCTION DatetoQuarter(@dqdate datetime)RETURNS char(6)ASBEGIN RETURN(datename(q,@dqdate)+'Q'+datename(yyy

y,@dqdate))END

例、创建工龄工资计算函数

Page 63: 第9章   transact sql程序设计

9.2.2 用户定义函数

调用函数

select emp.dbo.wage(‘1996-1-1’,getdate(),20)as work_year_wage运行结果如下:

Page 64: 第9章   transact sql程序设计

9.2.2 用户定义函数

内嵌表值函数的语法格式:

CREATE FUNCTION [owner_name.] function_name

( [{@parameter_name [AS] scalar_parameter_data_type [=default ] } [ ,...n ] ] )

RETURNS TABLE

[ WITH < function_option > [ [,] ...n ] ]

[ AS ]

RETURN [ ( ] select_stmt [ ) ]

Page 65: 第9章   transact sql程序设计

9.2.2 用户定义函数

例 9-19 创建用户定义函数 goodsq ,返回输入商品编号的商品名称和库存量。

CREATE FUNCTION goodsq(@goods_id varchar(30))RETURNS TABLEASRETURN(SELECT goods_name,stock_quantity FROM goods WHERE goods_id =@goods_id)

Page 66: 第9章   transact sql程序设计

9.2.2 用户定义函数

例 9-19 创建用户定义函数 goodsq ,返回输入商品编号的商品名称和库存量。

use northwind

go

CREATE FUNCTION goodsq(@product_id int)

RETURNS TABLE

AS

RETURN(SELECT productid,productname

FROM products

WHERE productid=@product_id)

Page 67: 第9章   transact sql程序设计

9.2.2 用户定义函数

多语句表值函数的语法格式:CREATE FUNCTION [owner_name.] function_name( [ { @parameter_name [AS] scalar_parameter_data_type [ = default

] } [ ,...n ] ] ) RETURNS @return_variable TABLE < table_type_definition >[ WITH < function_option > [ [,] ...n ] ] [ AS ]BEGIN function_body RETURNEND

Page 68: 第9章   transact sql程序设计

9.2.2 用户定义函数

例 9-20 根据输入的订单编号,返回该订单对应商品的编号、名称、类别编号、类别名称。

CREATE FUNCTION good_info(@in_o_id varchar(10))RETURNS @goodinfo TABLE(o_id char(6), g_id char(6), g_name varchar(50))ASBEGIN DECLARE @g_id varchar(10),@g_name varchar(30) SELECT @g_id=goods_id FROM sell_order1 WHERE order_id1=@in_o_id SELECT @g_name=goods_name FROM goods2 WHERE goods_id=@g_id INSERT INTO @goodinfo VALUES(@in_o_id,@g_id,@g_name) RETURNEND

Page 69: 第9章   transact sql程序设计

9.2.2 用户定义函数

① 在企业管理器中选择要创建用户定义函数的数据库(如 Sales),在数据库对象“用户定义函数”项上单击右键,从弹出的快捷菜单中选择“新建用户定义的函数 ...” 选项,出现如图所示的“用户定义函数属性”对话框。

(2) 使用企业管理器创建用户定义函数

Page 70: 第9章   transact sql程序设计

9.2.2 用户定义函数

② 在“用户定义函数属性”对话框的文本框中指定函数名称(如 numtostr),编写函数的代码。

③ 单击“检查语法”按钮,出现“语法检查成功”消息框后,单击“确定”按钮,将用户定义函数对象添加到数据库中。

Page 71: 第9章   transact sql程序设计

9.2.2 用户定义函数

2. 执行用户定义函数

使用函数需要指出函数所有者,即为函数加上所有者权限作为前缀。其语法格式如下:

[database_name.]owner_name.function_name ([argument_expr] [, ...] )

Page 72: 第9章   transact sql程序设计

9.2.2 用户定义函数

例如,调用例 9-18 创建的用户定义函数 DatetoQuarter

SELECT dbo.DatetoQuarter ('2006-8-5')

运行结果为:3Q2006

调用例 9-20 创建的用户定义函数 good_info ,使用以下语句:SELECT * FROM dbo.good_info('S00002')

运行结果为表的记录,如图 9-3所示。

Page 73: 第9章   transact sql程序设计

9.2.2 用户定义函数

3. 修改和删除用户定义函数 用企业管理器修改用户定义函数,选择要修改函数,单击

右键,从快捷菜单中选择“属性”选项,打开图 9-2所示的“用户定义函数属性”对话框。在该对话框中可以修改用户定义函数的函数体、参数等。从快捷菜单中选择“删除”选项,则可删除用户定义函数。

用 ALTER FUNCTION 命令也可以修改用户定义函数。此命令的语法与 CREAT FUNCTION 相同,使用 ALTER FUNCTION 命令相当于重建一个同名的函数。

使用 DROP FUNCTION 命令删除用户定义函数,其语法如下:DROP FUNCTION { [ owner_name .] function_name } [ ,...n ]其中, function_name 是要删除的用户定义的函数名称。

Page 74: 第9章   transact sql程序设计

9.2.2 用户定义函数

例如,删除例 9-18 创建的用户定义函数

DROP FUNCTON DatetoQuarter删除用户定义函数时,可以不加所有者前

缀。

Page 75: 第9章   transact sql程序设计

9.3 程序控制流语句9.3.1 语句块和注释9.3.2 选择控制9.3.3 循环控制9.3.4 批处理

Page 76: 第9章   transact sql程序设计

9.3 程序控制流语句

9.3.1 语句块和注释 Transact-SQL提供了控制流语言的特殊关

键字和用于编写过程性代码的语法结构,可进行顺序、分支、循环、存储过程、触发器等程序设计,编写结构化的模块代码,并放置到数据库服务器上。

Page 77: 第9章   transact sql程序设计

9.3.1 语句块和注释

BEGIN...END 用来设定一个语句块,将在 BEGIN...END 内的所有语句视为一个逻辑单元执行。

语句块 BEGIN...END 的语法格式为:BEGIN

{ sql_statement | statement_block }

END

1. 语句块 BEGIN...END

Page 78: 第9章   transact sql程序设计

9.3.1 语句块和注释

USE employee

GO

DECLARE @linkman_name char(8)

BEGIN

SELECT @linkman_name=(SELECT linkman_name FROM customer WHERE customer_id LIKE ‘1001')

SELECT @linkman_name

END

例 9-21 显示 Sales 数据库中 customer 表的编号为‘ 1001' 的联系人姓名。

Page 79: 第9章   transact sql程序设计

9.3.1 语句块和注释

在 BEGIN...END 中可嵌套另外的 BEGIN...END 来定义另一程序块。例 9-22 语句块嵌套举例。

DECLARE @errorcode int,@nowdate dateTIMEBEGIN SET @nowdate=getdate() INSERT sell_order(order_date,send_date,arriver_date,custo

m_id) VALUES(@nowdate,@nowdate+5,@nowdate+10,'C0002') SELECT @errorcode=@@error IF @errorcode>0 BEGIN RAISERROR(' 当表 sell_order 插入数据时发生错误 !',16,1) RETURN ENDEND

Page 80: 第9章   transact sql程序设计

9.3.1 语句块和注释

2. 注释 有两种方法来声明注释:

单行注释多行注释。

Page 81: 第9章   transact sql程序设计

9.3.1 语句块和注释

( 1 )单行注释 在语句中,使用两个连字符“ --” 开头,则从此开始的整行或者行的一部分就成为了注释,注释在行的末尾结束。--This is a comment.Whole line will be ignored.SELECT employee_name, address --查询所有姓钱的员工

FROM employeeWHERE employee_name LIKE '钱%'

注释的部分不会被 SQL Server执行。

Page 82: 第9章   transact sql程序设计

9.3.1 语句块和注释

( 2 )多行注释 多行注释方法是 SQL Server 自带特性,可以注释大块跨越多行的代码,它必须用一对分隔符“ /* */” 将余下的其他代码分隔开。/*This is a commnet .All these lines will be ignored.*//* List all employees.*/SELECT * FROM employee

注释并没有长度限制。 SQL Server 文档禁止嵌套多行注释,但单行注释可以嵌套在多行注释中。/* --List all employees.SELECT * FROM employee*/

Page 83: 第9章   transact sql程序设计

选择结构

选择结构可以使用条件语句来实现。

语法格式: IF < 布尔表达式 >

<SQL 语句 >|< 语句块 >

[ELSE

<SQL 语句 >|< 语句块 >]

Page 84: 第9章   transact sql程序设计

9.3.2 选择控制

IF (SELECT avg(unit_price) FROM goods

WHERE supplier_id='S001')>$9799.0

SELECT 'supplier_id 为 S001 的商品的平均单价比 9799 大 '

ELSE

SELECT 'supplier_id 为 S001 的商品的平均单价比 9799 小 '

运行结果如下:supplier_id 为 S001 的商品的平均单价比 9799 大

例 9-23 判断表 goods 中 supplier_id 为“ S001” 的商品的平均单价是否大于 9799 。

Page 85: 第9章   transact sql程序设计

9.3.2 选择控制

DECLARE @lname varchar(40),@msg varchar(255)SELECT @lname='陈晓兵 'IF EXISTS(SELECT * FROM department WHERE manager=@lname) BEGIN SELECT @msg=' 有人名为 '+@lname SELECT @msg ENDELSE BEGIN SELECT @msg=' 没有人名为 '+@lname SELECT @msg END

运行结果为:有人名为陈晓兵

例 9-24 用 EXISTS 确定表 department 中是否存在“陈晓兵”。

Page 86: 第9章   transact sql程序设计

例 查询学号为例 查询学号为 10011001 的学生。的学生。脚本: if exists(select sno from s where sno='0001')

print ' 找到 '

else

print ' 未找到 '

选择结构

Page 87: 第9章   transact sql程序设计

例 查询标识号为’例 查询标识号为’ 5678’5678’ 的出版商出版的任何书的的出版商出版的任何书的信息。信息。

脚本: if exists(select * from title where pub_id=‘5678') begin print ‘ 该出版商包含如下书籍:‘ select * from title where pub_id=‘5678’ end else print ' 未找到 '

选择结构

Page 88: 第9章   transact sql程序设计

9.3.2 选择控制

例 9-25 嵌套 IF...ELSE 语句的使用。IF (SELECT SUM(order_num) FROM sell_order)>50

PRINT ' 他们是最佳的客户 '

ELSE

IF (SELECT SUM(order_num) FROM sell_order)>30

PRINT '必须与他们保持联络 '

ELSE

PRINT '再想想办法吧 !!‘

Page 89: 第9章   transact sql程序设计

例 查询学号为例 查询学号为 10011001 的学生选修的课程号为的学生选修的课程号为 C0C00202 的成绩等级(条件语句的嵌套)。的成绩等级(条件语句的嵌套)。

脚本:

选择结构

Page 90: 第9章   transact sql程序设计

课堂练习:

查询在部门’办公室’的人员姓名

Page 91: 第9章   transact sql程序设计

9.3.2 选择控制

2. CASE 函数 CASE 函数计算多个条件并为每个条件返回单个值。 (1) 简单 CASE 函数:将某个表达式与一组简单表达式进行比较以确定结果。CASE input_expression

WHEN when_expression THEN result_expression

[ ...n ]

[ELSE else_result_expression ]

END

(2) CASE搜索函数, CASE 计算一组逻辑表达式以确定结果。CASE

WHEN Boolean_expression THEN result_expression

[ ... n ]

[ ELSE else_result_expression ]

END

Page 92: 第9章   transact sql程序设计

9.3.2 选择控制

例 9-26 使用简单 CASE 函数将 goods 表中的商品分类重命名,以使之更易理解。

SELECT CASE classification_id WHEN 'P001' THEN '笔记本计算机 ' WHEN 'P002' THEN '激光打印机 ' WHEN 'P003' THEN '喷墨打印机 ' WHEN 'P004' THEN '交换机 ' ELSE ' 没有这种品牌 ' END AS Classification, goods_name AS 'Goods Name', unit_price AS PriceFROM goodsWHERE unit_price IS NOT NULL

Page 93: 第9章   transact sql程序设计

9.3.2 选择控制

SELECT goods_name AS 商品名称 , CASE WHEN stock_quantity-order_quantity<=3 THEN '紧急进货 ' WHEN stock_quantity-order_quantity>3 and stock_quantity-order_quantity<=10 THEN '暂缓进货 ' WHEN stock_quantity-order_quantity>10 THEN ' 货物充足 ' END AS 进货判断FROM goods

例 9-27 根据 goods 表中库存货物数量与订货量之差,使用 CASE 搜索函数判断该商品是否进货。

Page 94: 第9章   transact sql程序设计

课堂练习:

上调员工工资,工资级别为 1 的上调 8% ,工资级别为 2 的上调 7% ,工资级别为 3 的上调 6% ,其他上调 5% 。

Page 95: 第9章   transact sql程序设计

循环结构

循环结构可以使用循环语句来实现。 语法格式: WHILE < 布尔表达式 >

<SQL 语句 >|< 语句块 >

中断语句: BREAK

短路语句: CONTINUE

Page 96: 第9章   transact sql程序设计

9.3 程序控制流语句例 9-30 将 goods 表中库存数最大的商品每次订购 2 件,计算如此需要多少次订购才能使库存数不够一次订购。

DECLARE @count int,@maxstockid char(6),@maxstock floatSET @count=0SET @maxstock=(SELECT max(stock_quantity) FROM goods)SET @maxstockid=(SELECT goods_id FROM goods WHERE stock_quantity=@maxstock)SELECT @maxstockid,@maxstockWHILE (@maxstock> (SELECT order_quantity FROM goods WHERE goods_id=@maxstocki

d))BEGIN UPDATE goods SET order_quantity=order_quantity+2 WHERE goods_id=@maxstockid SET @count=@count+1ENDSELECT @count

运行结果如下:8

Page 97: 第9章   transact sql程序设计

9.3 程序控制流语句

DECLARE @x int,@y int,@c intSET @x=1,@y=1WHILE @x<3BEGIN print @x WHILE @y<3 BEGIN SELECT @c=100*@x+@y print @c SELECT @y=@y+1 END SELECT @x=@x+1 SELECT @y=1END

运行结果:

1

101

102

2

201

202

Page 98: 第9章   transact sql程序设计

9.3 程序控制流语句例 9-31 对于 goods 表,如果平均库存少于 12 , WHILE 循环就将各记录库存增加 5% ,再判断最高库存是否少于或等于 25 ,是则 WHILE 循环重新启动并再次将各记录库存增加 5% 。当循环不断地将库存增加直到最高库存超过 25 时,然后退出 WHILE 循环。

/*执行循环,直到库存平均值超过 12*/WHILE(SELECT avg(stock_quantity) FROM goods)<12BEGIN UPDATE goods SET stock_quantity=stock_quantity*1.05 SELECT max(stock_quantity) FROM goods /* 如果最大库存值超过 25 ,则用 BREAK退出 WHILE循环,否则继续循环 *

/ IF(SELECT max(stock_quantity) FROM goods)>25 BEGIN PRINT ' 库存太多了 ' BREAK END ELSE CONTINUEEND

Page 99: 第9章   transact sql程序设计

9.3 程序控制流语句

BREAK 语句让程序跳出循环, CONTINUE 语句让程序跳过 CONTINUE 命令之后的语句,回到 WHILE循环的第一行命令,重新开始循环。

BREAK 或 CONTINUE 语句

Page 100: 第9章   transact sql程序设计

9.3 程序控制流语句

DECLARE @s int,@n int,@t int,@c intSET @s=0SET @n=1WHILE @n<=10BEGIN SET @c=1 SET @t=1 WHILE @c<=@n BEGIN SET @t=@t*@c SET @c=@c+1 END SET @s=@s+@t SET @n=@n+1ENDSELECT @s,@n

例 9-32 计算 s=1!+2!+…+10! 。

Page 101: 第9章   transact sql程序设计

1 、求 1~10 之间的素数和。脚本:

2 、求 100~200 之间的全部素数。脚本:

课堂练习:

Page 102: 第9章   transact sql程序设计

转移语句

转移语句将程序的执行流程无条件转移到指定的标号处。 语法格式: GOTO < 标号 >

定义标号时,应在标号名后面加上冒号。 GOTO 语句常用在循环语句和条件语句内,使程序跳出循环或进行分支处理。

Page 103: 第9章   transact sql程序设计

例 9-11 求 10的阶乘。

脚本:DECLARE @s int,@times int set @s=1set @times=1label1:set @s=@s*@timesset @times=@times+1if @times<=10 goto label1print ' 结果为 :'+str(@s)

Page 104: 第9章   transact sql程序设计

9.3.2 选择控制

例 9-28 使用 GOTO 语句改变程序流程。

DECLARE @x int

SELECT @x=1

label_1:

SELECT @x

SELECT @x=@x+1

WHILE( IF) @x<6

GOTO label_1

Page 105: 第9章   transact sql程序设计

等待语句

等待语句挂起一个程序中语句的执行,直到指定的某一时间点到来或在一定的时间间断之后才继续执行。

语法格式: WAITFOR DELAY '< 时间间隔 >'|TIME '< 时间 >'

其中,时间间隔以及时间均为 datetime 类型,格式为“ hh:mm:ss” ,分别说明等待的时间长度和时间点,在 time 内不能指定日期。

Page 106: 第9章   transact sql程序设计

例 设置等待一小时后执行查询。例 设置等待一小时后执行查询。脚本: begin waitfor delay '1:00:00' select * from s end

例 设置到十点整执行查询。例 设置到十点整执行查询。脚本: begin waitfor time '10:00:00' select * from s end

等待语句

Page 107: 第9章   transact sql程序设计

返回语句

返回语句结束执行,使程序无条件返回,其后面的语句不再执行。 语法格式: RETURN [< 整数表达式 >]

存储过程可以使用 RETURN 语句向调用者返回一个整数值。在 SQL Server 2000 中,存储过程返回值为 0 时,表示存储过程成功执行。

Page 108: 第9章   transact sql程序设计

9.3.2 选择控制

例 9-29 RETURN 语句应用示例。

DECLARE @x int,@y int

SELECT @x=1,@y=2

IF @x>@y

RETURN

ELSE

RETURN

Page 109: 第9章   transact sql程序设计

9.3 程序控制流语句

9.3.4 批处理 一个批处理是—条或多条 Transact-SQL 语句的集合。 SQL Server服务器对批处理的处理分为四个阶段:

分析阶段,服务器检查命令的语法,验证表和列的名字的合法性 优化阶段,服务器确定完成一个查询的最有效的方法; 编译阶段,生成该批处理的执行计划; 运行阶段,—条一条地执行该批处理中的语句。

批处理最重要的特征就是它作为一个不可分的实体在服务器上解释和执行。在一些情况下批处理被隐式地设定。例如,用查询分析器来执行一组 Transact-SQL 语句,这组语句将被视为一个批处理来对待。

Page 110: 第9章   transact sql程序设计

9.3 程序控制流语句

SQL Server 有以下几种指定批处理的方法。(1) 应用程序作为一个执行单元发出的所有 SQL 语句构成一

个批处理,并生成单个执行计划。(2) 存储过程或触发器内的所有语句构成一个批处理。每个

存储过程或触发器都编译为一个执行计划。(3) 由 EXECUTE 语句执行的字符串是一个批处理,并编译

为一个执行计划。例如,EXEC ('SELECT * FROM employee')

(4) 由 sp_executesql 系统存储过程执行的字符串是一个批处理,并编译为一个执行计划。例如,execute sp_executesql N'SELECT * from Sales.dbo.employee'

1. 批处理的指定

Page 111: 第9章   transact sql程序设计

9.3 程序控制流语句

GO 是批处理的结束标志。当编译器执行到 GO 时会把 GO 前面的所有语句当成一个批处理来执行。

GO 命令和 Transact-SQL 语句不可处在同一行上。但在GO 命令行中可以包含注释。

在批处理的第一条语句后执行任何存储过程必须包含 EXECUTE关键字。局部 ( 用户定义 ) 变量的作用域限制在一个批处理中,不可在 GO 命令后引用。

RETURN 可在任何时候从批处理中退出,而不执行位于RETURN 之后的语句。

2. 批处理的结束与退出

Page 112: 第9章   transact sql程序设计

9.3 程序控制流语句

USE SalesGO -- 批处理结束标志CREATE VIEW employee_infoASSELECT * FROM employeeGO-- CREATE VIEW 语句与其他语句隔离SELECT * FROM employee_infoGO

例 9-33 创建一个视图,使用 GO 命令将 CREATE VIEW 语句与批处理中的其他语句 ( 如 USE 、 SELECT语句等 )隔离。

Page 113: 第9章   transact sql程序设计

9.4 游标管理与应用9.4.1 游标概述9.4.2 声明游标9.4.3 使用游标9.4.4 游标的应用9.4.5 使用系统存储过程管理游标

Page 114: 第9章   transact sql程序设计

9.4.1 游标概述9.4 游标管理与应用

1. 游标种类(1)Transact-SQL 游标:是由 DECLARE CURSOR 语句定义,主要用在服务器上,由从客户端发送给服务器的 Transact-SQL语句或批处理、存储过程、触发器中的 Transact-SQL 语句进行管理。 Transact-SQL 游标不支持提取数据块或多行数据。

(2)API 游标:支持在 OLE DB 、 ODBC 以及 DB_library 中使用游标函数,主要用在服务器上。每一次客户端应用程序调用 API 游标函数, SQL Server 的 OLE DB提供者、 ODBC驱动器或 DB_library 的动态链接库 (DLL)都会将这些客户请求送给服务器以对 API 游标进行处理。

(3)客户游标:当客户机缓存结果集时才使用。在客户游标中,有一个默认的结果集被用来在客户机上缓存整个结果集。客户游标仅支持静态游标。一般情况下,服务器游标能支持绝大多数的游标操作,但不支持所有的 Transact-SQL 语句或批处理,所以客户游标常常仅被用作服务器游标的辅助。

由于 API 游标和 Transact-SQL 游标使用在服务器端,所以被称为服务器游标或后台游标,而客户端游标被称为前台游标。

Page 115: 第9章   transact sql程序设计

2. 服务器游标与默认结果集的比较9.4.1 游标概述

SQL Server 以两种方式为用户返回结果集:默认结果集和服务器游标。

(1)默认结果集具有的特点:开销小;取数据时提供最大性能;仅支持默认的单进、只读游标功能;返回结果行时一次一行;连接时一次只支持一个活动语句;支持所有 Transact-SQL 语句。

(2)服务器游标具有的持点:支持所有游标功能;可以为用户返回数据块;在单个连接上支持多个活动语句;以性能补偿游标功能;不支持所有返回多于一行结果集的 Transact-SQL 语句。

使用游标不如使用默认结果集的效率高。在默认结果集中,客户端只向服务器发送要执行的语句。而使用服务器游标时,每个 FETCH 语句都必须从客户端发往服务器,再在服务器中分析此语句并将它编译为执行汁划。

Page 116: 第9章   transact sql程序设计

3. 服务器游标与客户端游标的比较9.4.1 游标概述

使用服务器游标比使用客户游标有以下几方面的优点:(1) 性能:如果要在游标中访问部分数据,使用服务器游标

将提供最佳性能,因为只有被取到的数据在网络上发送,客户游标在客户端存取所有结果集。

(2)更准确的定位更新:服务器游标直接支持定位操作,如 UPDATE 和 DELETE 语句,客户游标通过产生 Transact-SQL搜索 UPDATE 语句模拟定位游标更新,如果多行与 UPDATE 语句的 WHERE子句的条件相匹配将导致无意义更新。

(3) 内存使用:使用服务器游标时,客户端不需要高速存取大量数据或者保持有关游标位置的信息,这些都由服务器来完成。

(4) 多活动语句:使用服务器游标时,结果不会存留在游标操作之间的连接上,这就允许同时拥有多个活动的基于游标的语句。

Page 117: 第9章   transact sql程序设计

9.4.1 游标概述

SQL Server支持 4种类型的服务器游标,它们是单进游标、静态游标、动态游标和键集驱动游标。

(1) 单进游标只支持游标按从前向后顺序提取数据,游标从数据库中提取一条记录并进行操作,操作完毕后,再提取下一条记录。

(2)静态游标也称为快照游标,它总是按照游标打开时的原样显示结果集,并不反映在数据库中对任何结果集成员所做的修改,因此不能利用静态游标修改基表中的数据。静态游标打开时的结果集存储在数据库 tempdb 中。静态游标始终是只读的。

(3)动态游标也称为敏感游标,与静态游标相对,当游标在结果集中滚动时,结果集中的数据记录的数据值、顺序和成员的变化均反映到游标上,用户所做的各种操作均可通过游标反映。

(4) 键集驱动游标介于静态游标和动态游标之间,兼有两者的特点。打开键集驱动游标后,游标中的成员和行顺序是固定的。键集驱动游标由一套惟一标识符控制,这些惟一标识符就是键集。用户对基表中的非关键值列插入数据或进行修改造成数据值的变化,在整个游标中都是可见。键集驱动游标的键集在游标打开时建立在数据库 tempdb 中。

4. 服务器游标类型

Page 118: 第9章   transact sql程序设计

9.4.2 声明游标

9.4 游标管理与应用

SQL Server 游标具有下面的处理过程:(1)声明游标,定义其特性,如游标中的行是否可以被更新。

(2) 执行 Transact-SQL 语句生成游标。(3) 在游标中检索要查看的行。从游标中检索一行或几

行的操作称为取数据。向前或向后执行取数据操作来检索行的行为称为滚动。

(4)关闭游标。

Page 119: 第9章   transact sql程序设计

声明客户端游标的步骤9.4 游标管理与应用

创建一个新的 Visual Basic 项目,添加该 DataGrid 控件,然后添加数据环境。

配置为使用 Microsoft Jet 4.0 OLE DB 提供程序数据环境,并选择数据库文件 Nwind.mdb 。 (数据库文件随 Visual Basic 6.0 和典型的目录是 C:\Program Files \Microsoft Visual Studio\VB98\NWIND.MDB 。

创建新命令,产品,如打开表。 打开新创建的 Command 属性 对话框中,然后单击 高级 选项会确保设置该

命令以使用客户端游标和 BatchOptimistic 锁定类型。 配置数据环境和命令的 DataGrid 控件的 DataSource 和 DataMemeber

属性。 运行该项目。 修改第一行,第二列 (ProductName) 的单元格中的值。 单击所的 DataGrid 中的另一个单元格并请注意更改更新到数据库无需调用

UpdateBatch 注意 : 通过重新运行该程序验证更改。

Page 120: 第9章   transact sql程序设计

9.4.2 声明游标

语法格式如下:DECLARE cursor_name [ INSENSITIVE ] [ SCROLL ]

CURSOR

FOR select_statement

[ FOR { READ ONLY | UPDATE [ OF column_name [ ,...n ] ] } ]

1. SQL-92游标定义格式

Page 121: 第9章   transact sql程序设计

9.4.2 声明游标

表 9-13 SCROLL的取值

SCROLL选项 含 义

FIRST 提取游标中的第一行数据

LAST 提取游标中的最后一行数据

PRIOR 提取游标当前位置的上一行数据

NEXT 提取游标当前位置的下一行数据

RELATIVE n 提取游标当前位置之前或之后的第 n行数据 (n为正表示向后,n为负表示向前 )

ABSULUTE n 提取游标中的第 n行数据

Page 122: 第9章   transact sql程序设计

9.4.2 声明游标

例 9-34 使用 SQL-92标准的游标声明语句声明一个游标,用于访问 Sales 数据库中的 goods 表的信息。

USE Sales

GO

DECLARE Goods_cursor CURSOR

FOR

SELECT * FROM Goods

FOR READ ONLY

Page 123: 第9章   transact sql程序设计

9.4.2 声明游标

语法格式如下:DECLARE cursor_name CURSOR [ LOCAL | GLOBAL ] [ FORWARD_ONLY | SCROLL ] [ STATIC | KEYSET | DYNAMIC | FAST_FORWARD ] [ READ_ONLY | SCROLL_LOCKS | OPTIMISTIC ] [ TYPE_WARNING ] FOR select_statement [ FOR UPDATE [ OF column_name [ ,...n ] ] ]

2. Transact-SQL扩展游标定义格式

Page 124: 第9章   transact sql程序设计

9.4.2 声明游标

例 9-35 为 customer 表定义一个全局滚动动态游标,用于访问顾客的编号、姓名、地址、电话信息。

DECLARE cur_customer CURSORGLOBAL SCROLL DYNAMICFORSELECT customer_id,customer_name,address,tel

phoneFROM customer

Page 125: 第9章   transact sql程序设计

9.4 游标管理与应用

9.4.3 使用游标1. 打开游标

游标声明之后,必须打开才能使用。打开游标的语法格式如下:OPEN {{[GLOBAL] cursor_name} | cursor_varia

ble_name } 例如,打开例 9-35所声明的游标操作:

OPEN cur_customer

Page 126: 第9章   transact sql程序设计

9.4.3 使用游标

2. 读取游标 一旦游标被成功打开,就可以从游标中逐行地读

取数据,以进行相关处理。从游标中读取数据主要使用 FETCH 命令。其语法格式为:FETCH [ [NEXT|PRIOR|FIRST|LAST |ABSOLUTE {n|@nvar} |RELATIVE {n|@nvar}] FROM] {{[GLOBAL] cursor_name}| cursor_variable_name } [INTO @variable_name [ ,...n ]]

Page 127: 第9章   transact sql程序设计

9.4.3 使用游标

表 9-14 @@fetch_status变量

返回值 描 述

0 FETCH命令已成功执行

-1 FETCH命令失败或者行数据己超出了结果集

-2 所读取的数据已经不存在。

Page 128: 第9章   transact sql程序设计

9.4.3 使用游标

OPEN cur_customerFETCH NEXT FROM cur_customer

/* 取第一个数据行 */

WHILE @@fetch_status = 0 /* 检查@@fetch_status 是否还有数据可取 */

BEGIN FETCH NEXT FROM cur_customerEND

例 9-36 打开例 9-35 中声明的游标,读取游标中的数据。

Page 129: 第9章   transact sql程序设计

9.4.3 使用游标

CLOSE 的语法格式为:CLOSE {{[ GLOBAL ] cursor_name } | cursor_va

riable_name } 例如,关闭例 9-35 中的游标 cur_customer

的命令:CLOSE cur_customer

游标 cur_customer 在关闭后,仍可用 OPEN 语句打开继续读取数据行。

3. 关闭游标

Page 130: 第9章   transact sql程序设计

9.4.3 使用游标

DEALLOCATE 命令删除游标与游标名或游标变量之间的联系,并且释放游标占用的所有系统资源。其语法格式为:DEALLOCATE {{ [ GLOBAL ] cursor_name } | cursor_variable_na

me } 一旦某个游标被删除,在重新打开之前,必需再次对其进

行声明。 例如,释放例 9-35所定义的游标 cur_customer 。

DEALLOCATE cur_customer DEALLOCATE cursor_variable_name 语句只删除对游标

命名变量的引用。直到批处理、存储过程或触发器结束时变量离开作用域,才释放变量。

4. 释放游标

Page 131: 第9章   transact sql程序设计

9.4 游标管理与应用

9.4.4 游标的应用1. 用游标修改和删除表数据 定位修改游标数据的语法格式为:

UPDATE table_name SET {column_name={expression | DEFAULT | NULL }[, ... n]WHERE CURRENT OF {{[GLOBAL] cursor_name} | cursor_variab

le_name} 删除游标数据的语法格式为:

DELETE FROM table_nameWHERE CURRENT OF {{[GLOBAL] cursor_name} | cursor_variab

le_name}

Page 132: 第9章   transact sql程序设计

9.4.4 游标的应用

例 9-37 定义游标 cur_customer ,通过 cur_customer 更新 customer 表中的 customer_name 和 linkman_name 列。DECLARE cur_customer CURSORFORSELECT * FROM customerFOR UPDATE OF customer_name,linkman_name /* 该两列可更新 */OPEN cur_customer /*打开 cur_customer 游标 */FETCH NEXT FROM cur_customer /* 将第一行数据放入缓冲区,以便更新操作 */UPDATE customerSET customer_name='南方体育用品公司 ',linkman_name='李强 'WHERE CURRENT OF cur_customerCLOSE cur_customer /*关闭 cur_customer 游标 */

Page 133: 第9章   transact sql程序设计

9.4.4 游标的应用

若要删除 customer 表的一行数据,则使用以下命令替换例 9-37 中的 UPDATE 语句,就可以删除通过游标读入的一行数据。DELETE FROM customer

WHERE CURRENT OF cur_customer

Page 134: 第9章   transact sql程序设计

9.4.4 游标的应用

2. 使用游标变量

CURSOR关键字还可以作为变量类型来使用,此时,必须要将 CURSOR 进行变量声明。其语法格式为:DECLARE {@cursor_variable_name CURSOR } [ ,...n]

Page 135: 第9章   transact sql程序设计

9.4.4 游标的应用

游标与一个游标变量相关联的方法

(1) 分别定义游标变量与游标,再将游标赋给游标变量。DECLARE @cur_var CURSOR /* 定义游标变量 */

DECLARE cur_customer CURSOR

FOR SELECT * FROM customer /* 定义游标 */

SET @cur_var=cur_customer

/* 设置游标与游标变量的关联 */

Page 136: 第9章   transact sql程序设计

9.4.4 游标的应用

(2) 定义游标变量后,通过 SET 命令直接创建游标与游标变量关联

DECLARE @cur_var CURSOR /* 定义游标变量 */

SET @cur_var=CURSOR SCROLL KEYSET FOR

SELECT * FROM customer

/* 创建游标并与游标变量的关联 */

Page 137: 第9章   transact sql程序设计

9.4.4 游标的应用

DECLARE @cur_var cursor

SET @cur_var =cur_customer

OPEN @cur_var

FETCH NEXT FROM @cur_var

CLOSE @cur_var

DEALLOCATE @cur_var

例 9-38 通过游标变量来操作例 9-35 所声明的游标 cur_customer ,操作完成后删除游标变量。

Page 138: 第9章   transact sql程序设计

9.4.4 游标的应用

在游标定义语句中使用了关键字 SCROLL ,则可以用 FETCH 语句在游标集合内向前或向后移动,也可以直接跳到集合的某一条记录。

例 9-39 定义可以任意移动的游标。DECLARE cur_customer CURSOR SCROLLREAD_ONLYFOR SELECT * FROM customer

3. 滚动游标

Page 139: 第9章   transact sql程序设计

9.4.4 游标的应用

用 FETCH 语句将记录指针滚动记录

OPEN cur_customer

FETCH NEXT FROM cur_customer

FETCH PRIOR FROM cur_customer

FETCH FIRST FROM cur_customer

FETCH LAST FROM cur_customer

FETCH ABSOLUTE 5 FROM cur_customer

FETCH RELATIVE -2 FROM cur_customer

Page 140: 第9章   transact sql程序设计

9.4 游标管理与应用

9.4.5 使用系统存储过程管理游标1. sp_cursor_list sp_cursor_list 显示在当前作用域内的游标及其属性

sp_cursor_list [@cursor_return=]cursor_variable_name OUTPUT, [@cursor_scope=]cursor_scope

表 9-15 游标作用域范围值cursor_scope值 描 述

1 表示返回所有的 LOCAL游标2 表示返回所有的 GLOBAL游标3 表示 LOCAL、 GLOBAL游标都返回

Page 141: 第9章   transact sql程序设计

9.4.5 使用系统存储过程管理游标例 9-40 声明一个键值驱动游标,并使用 sp_cursor_list 报告该游标的特性。

DECLARE employee_cur CURSOR KEYSET FORSELECT employee_name FROM EmployeeWHERE employee_name LIKE '肖%'OPEN employee_curDECLARE @report CURSOR /*声明游标 @report 存储来自 sp_cursor_list 的信息 */

/*执行 sp_cursor_list 将信息送游标变量 @report*/EXEC master.dbo.sp_cursor_list @cursor_return = @report OUTPUT,@cursor_sco

pe = 2FETCH NEXT FROM @reportWHILE (@@fetch_status <> -1)BEGIN FETCH NEXT FROM @reportENDCLOSE @reportDEALLOCATE @reportGOCLOSE employee_curDEALLOCATE employee_curGO

Page 142: 第9章   transact sql程序设计

9.4.5 使用系统存储过程管理游标

sp_describe_cursor 用来显示游标的属性。sp_describe_cursor [ @cursor_return =] output_cursor_v

ariable OUTPUT { [, [ @cursor_source = ] N'local', [@cursor_identity = ]

N'local_cursor_name' ] | [, [ @cursor_source = ] N'global', [ @cursor_identity

= ] N'global_cursor_name' ] | [, [ @cursor_source = ] N'variable', [ @cursor_identit

y = ] N'input_cursor_variable' ] }

2. sp_describe_cursor

Page 143: 第9章   transact sql程序设计

9.4.5 使用系统存储过程管理游标

例 9-41 定义并打开一个全局游标,使用 sp_describe_cursor报告游标的特性。

DECLARE employee_cur CURSOR STATIC FORSELECT employee_name FROM employeeOPEN employee_curDECLARE @report CURSOREXEC master.dbo.sp_describe_cursor @cursor_return = @Report OUTPU

T, @cursor_source = N'global', @cursor_identity = N'employee_cur'FETCH NEXT from @reportWHILE (@@FETCH_STATUS <> -1)BEGIN FETCH NEXT from @reportENDCLOSE @reportDEALLOCATE @reportGOCLOSE employee_curDEALLOCATE employee_curGO

Page 144: 第9章   transact sql程序设计

本章小结

(1)数据类型是学习 Transact-SQL 语言的基础,不同种类的数据类型具有不同的精度和取值范围。

(2) 变量分为局部变量和全局变量两种。局部变量由 DECLARE 语句声明,可以由 SET 、 SELECT 或 UPDATE 语句赋值;全局变量不可由用户定义。

(3) Transact-SQL 的运算符分为算术运算符、位运算符、比较运算符、逻辑运算符、连接运算符,每种运算符都有专门的数据类型或操作数,各运算符间遵循一定的优先级。

(4) 函数是—组编译好的 Transact-SQL 语句。 SQL Server 2000支持的函数分为内置函数和用户定义函数两种类型。用户定义函数可以通过企业管理器和 Transact-SQL 语句来管理。 CREATE FUNCTION 、 ALTER FUNCTION 、 DROP FUNCTION 分别创建、修改、删除用户定义函数。用户定义函数的调用要在函数名前加所有者作为前缀。

(5) 程序控制流语句 BEGIN 和 END要一起使用,其功能是将语句块括起来。 IF…ELSE 语句根据条件来执行语句块。当程序有多个条件需要判断时,可以使用 CASE 函数实现。 WHILE循环可根据条件多次重复执行语句。 GOTO 语句会破坏程序结构化的特点,尽量不要使用。

(6) 游标是应用程序通过行来管理数据的一种方法。有 3种游标: Transact-SQL游标、 API服务器游标和客户游标。游标声明使用 DECLARE CURSOR 语句,游标的使用包括打开游标、读取数据、关闭游标、删除游标等,分别使用 OPEN 、 FETCH 、 CLOSE 、 DEARLLOCATE 语句。