② 利用 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 常量与变量
19.
③ 用SET 给局部变量赋值 SET 语句格式为: SET {@local_variable=expression} 使用 SET 初始化变量的方法与 SELECT 语句相同, 但一个 SET 语句只能为一个变量赋值 。 例 9-3 计算 employee 表的记录数并赋值给局部变量 @rows 。 DECLARE @rows int SET @rows=(SELECT COUNT(*) FROM employee) SELECT @rows 9.1.2 常量与变量
20.
例 声明一个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
① @@rowcount@@rowcount 存储前一条命令影响到的记录总数,除了 DECLARE 语句之外,其他任何语句都可以影响 @@rowcount 的值。 例如 DECLARE @rows int SELECT @rows=@@rowcount 9.1.2 常量与变量
23.
② @@error如果 @@error 为非 0 值,则表明执行过程中产生了错误,此时应当在程序中采取相应的措施加以处理。 @@error 的值与 @@rowcount 一样,会随着每一条 SQL Server 语句的变化而改变。 例 9-4 使服务器产生服务,并显示错误号。 raiserror('miscellaneous error message',16,1) /* 产生一个错误 */ if @@error<>0 SELECT @@error as 'last error' 运行结果: 服务器 : 消息 50000 ,级别 16 ,状态 1 ,行 1 miscellaneous error message last error 0 9.1.2 常量与变量
24.
例 9-5 捕捉例 9-4 中服务器产生的错误号,并显示出来。 DECLARE @my_error int RAISERROR('miscellaneous error message',16,1) SELECT @my_error=@@error IF @my_error<>0 SELECT @my_error as 'last error' 运行结果: 服务器 : 消息 50000 ,级别 16 ,状态 1 ,行 2 miscellaneous error message last error 50000 9.1.2 常量与变量
25.
③ @@trancount@@trancount 记录当前的事务数量,当某个事务当前并没有结束会话过程时, @@trancount 的值大于 0 。 ④ @@version @@version 的值代表服务器的当前版本和当前操作系统版本,是 SQL Server 中一项较实用的技术支持,通常对识别网络中某个未命名的服务器时非常有用。 ⑤ @@spid @@spid 返回当前用户进程的服务器进程 ID ,可以用来识别 sp_who 输出中的当前用户进程。
26.
例 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 常量与变量
1 .字符串函数 字符串函数用来实现对字符型数据的转换、查找、分析等操作,通常用做字符串表达式的一部分。表 9-7 中列出了 SQL Server 的常用字符串函数。 9.2.1 常用函数
42.
(1) 使用datalength 和 Len 函数 datalength 函数主要用于判断可变长字符串的长度,对于定长字符串将返回该列的长度。要得到字符串的真实长度,通常需要使用 rtrim 函数截去字符串尾部的空格。 Len 函数可以获取字符串的字符个数,而不是字节数,也不包含尾随空格。 9.2.1 常用函数
43.
例 9-10 从表 department 中读取 manger 列的各记录的实际长度。 SELECT Datalength(rtrim(manger)) AS 'DATALENGTH', Len(rtrim(manger)) AS 'LEN' FROM department 运行结果如下: DATALENGTH LEN 4 2 6 3 6 3 6 3 9.2.1 常用函数
表 9-10 SQL Server 的日期部分 9.2.1 常用函数 0~999 ms Millisecond 0~59 ss Second 0~59 mi Minute 0~23 hh Hour 1~7(Mon~Sun) dw Weekday 1~54 wk Week 1~31 dd Day 1~366 dy Dayofyear 1~12 mm Month 1~4 qq Quarter 1753~9999 yy Year 取值范围 写 法 日期部分
例 9-15 使用 datename 函数返回员工的出生日期的月份 (mm) 名称。 SELECT employee_name,datename(mm,birth_date) FROM employee 运行结果如下: 钱达理 December 东方牧 April 郭文斌 March 肖海燕 July 张明华 August 9.2.1 常用函数
例 9-17 利用 object_id 函数,根据表名返回该表的 ID 号。 SELECT name FROM sysindexes WHERE id=object_id('customer') 运行结果如下: name customer _WA_Sys_customer_id_75D7831F 9.2.1 常用函数
例 9-19 创建用户定义函数 goodsq ,返回输入商品编号的商品名称和库存量。 CREATE FUNCTION goodsq(@goods_id varchar(30)) RETURNS TABLE AS RETURN ( SELECT goods_name,stock_quantity FROM goods WHERE goods_id =@goods_id ) 9.2.2 用户定义函数
66.
例 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) 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)) AS BEGIN 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) RETURN END 9.2.2 用户定义函数
69.
① 在企业管理器中选择要创建用户定义函数的数据库(如Sales ),在数据库对象“用户定义函数”项上单击右键,从弹出的快捷菜单中选择“新建用户定义的函数 ...” 选项,出现如图所示的“用户定义函数属性”对话框。 (2) 使用企业管理器创建用户定义函数 9.2.2 用户定义函数
70.
② 在“用户定义函数属性”对话框的文本框中指定函数名称(如numtostr ),编写函数的代码。 ③ 单击“检查语法”按钮,出现“语法检查成功”消息框后,单击“确定”按钮,将用户定义函数对象添加到数据库中。 9.2.2 用户定义函数
3. 修改和删除用户定义函数用企业管理器修改用户定义函数,选择要修改函数,单击右键,从快捷菜单中选择“属性”选项,打开图 9-2 所示的“用户定义函数属性”对话框。在该对话框中可以修改用户定义函数的函数体、参数等。从快捷菜单中选择“删除”选项,则可删除用户定义函数。 用 ALTER FUNCTION 命令也可以修改用户定义函数。此命令的语法与 CREAT FUNCTION 相同,使用 ALTER FUNCTION 命令相当于重建一个同名的函数。 使用 DROP FUNCTION 命令删除用户定义函数,其语法如下: DROP FUNCTION { [ owner_name .] function_name } [ ,...n ] 其中, function_name 是要删除的用户定义的函数名称。 9.2.2 用户定义函数
BEGIN...END 用来设定一个语句块,将在 BEGIN...END内的所有语句视为一个逻辑单元执行。 语句块 BEGIN...END 的语法格式为: BEGIN { sql_statement | statement_block } END 1. 语句块 BEGIN...END 9.3.1 语句块和注释
78.
USE employee GODECLARE @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' 的联系人姓名。 9.3.1 语句块和注释
79.
在 BEGIN...END 中可嵌套另外的BEGIN...END 来定义另一程序块。 例 9-22 语句块嵌套举例。 DECLARE @errorcode int,@nowdate dateTIME BEGIN SET @nowdate=getdate() INSERT sell_order(order_date,send_date,arriver_date,custom_id) VALUES(@nowdate,@nowdate+5,@nowdate+10,'C0002') SELECT @errorcode=@@error IF @errorcode>0 BEGIN RAISERROR(' 当表 sell_order 插入数据时发生错误 !',16,1) RETURN END END 9.3.1 语句块和注释
( 1 )单行注释在语句中,使用两个连字符“ --” 开头,则从此开始的整行或者行的一部分就成为了注释,注释在行的末尾结束。 --This is a comment.Whole line will be ignored. SELECT employee_name, address -- 查询所有姓钱的员工 FROM employee WHERE employee_name LIKE ' 钱 %' 注释的部分不会被 SQL Server 执行。 9.3.1 语句块和注释
82.
( 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 */ 9.3.1 语句块和注释
DECLARE @lname varchar(40),@msgvarchar(255) SELECT @lname=' 陈晓兵 ' IF EXISTS(SELECT * FROM department WHERE manager=@lname) BEGIN SELECT @msg=' 有人名为 '+@lname SELECT @msg END ELSE BEGIN SELECT @msg=' 没有人名为 '+@lname SELECT @msg END 运行结果为: 有人名为陈晓兵 例 9-24 用 EXISTS 确定表 department 中是否存在“陈晓兵”。 9.3.2 选择控制
86.
例 查询学号为1001 的学生。 脚本: if exists(select sno from s where sno='0001') print ' 找到 ' else print ' 未找到 ' 选择结构
87.
例 查询标识号为’5678’ 的出版商出版的任何书的信息。 脚本: if exists(select * from title where pub_id=‘5678') begin print ‘ 该出版商包含如下书籍:‘ select * from title where pub_id=‘5678’ end else print ' 未找到 ' 选择结构
88.
例 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 ' 再想想办法吧 !!‘ 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 9.3.2 选择控制
92.
例 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 Price FROM goods WHERE unit_price IS NOT NULL 9.3.2 选择控制
93.
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 搜索函数判断该商品是否进货。 9.3.2 选择控制
例 9-30 将 goods 表中库存数最大的商品每次订购 2 件,计算如此需要多少次订购才能使库存数不够一次订购。 DECLARE @count int,@maxstockid char(6),@maxstock float SET @count=0 SET @maxstock=(SELECT max(stock_quantity) FROM goods) SET @maxstockid=(SELECT goods_id FROM goods WHERE stock_quantity=@maxstock) SELECT @maxstockid,@maxstock WHILE (@maxstock> (SELECT order_quantity FROM goods WHERE goods_id=@maxstockid)) BEGIN UPDATE goods SET order_quantity=order_quantity+2 WHERE goods_id=@maxstockid SET @count=@count+1 END SELECT @count 运行结果如下: 8 9.3 程序控制流语句
97.
DECLARE @x int,@yint,@c int SET @x=1,@y=1 WHILE @x<3 BEGIN print @x WHILE @y<3 BEGIN SELECT @c=100*@x+@y print @c SELECT @y=@y+1 END SELECT @x=@x+1 SELECT @y=1 END 9.3 程序控制流语句 运行结果: 1 101 102 2 201 202
98.
例 9-31 对于 goods 表,如果平均库存少于 12 , WHILE 循环就将各记录库存增加 5% ,再判断最高库存是否少于或等于 25 ,是则 WHILE 循环重新启动并再次将各记录库存增加 5% 。当循环不断地将库存增加直到最高库存超过 25 时,然后退出 WHILE 循环。 /* 执行循环,直到库存平均值超过 12*/ WHILE(SELECT avg(stock_quantity) FROM goods)<12 BEGIN 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 CONTINUE END 9.3 程序控制流语句
DECLARE @s int,@nint,@t int,@c int SET @s=0 SET @n=1 WHILE @n<=10 BEGIN 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+1 END SELECT @s,@n 例 9-32 计算 s=1!+2!+…+10! 。 9.3 程序控制流语句
例 9-11 求 10 的阶乘。 脚本: DECLARE @s int,@times int set @s=1 set @times=1 label1: set @s=@s*@times set @times=@times+1 if @times<=10 goto label1 print ' 结果为 :'+str(@s)
104.
例 9-28 使用 GOTO 语句改变程序流程。 DECLARE @x int SELECT @x=1 label_1: SELECT @x SELECT @x=@x+1 WHILE ( IF ) @x<6 GOTO label_1 9.3.2 选择控制
GO 是批处理的结束标志。当编译器执行到 GO时会把 GO 前面的所有语句当成一个批处理来执行。 GO 命令和 Transact-SQL 语句不可处在同一行上。但在 GO 命令行中可以包含注释。 在批处理的第一条语句后执行任何存储过程必须包含 EXECUTE 关键字。局部 ( 用户定义 ) 变量的作用域限制在一个批处理中,不可在 GO 命令后引用。 RETURN 可在任何时候从批处理中退出,而不执行位于 RETURN 之后的语句。 2. 批处理的结束与退出 9.3 程序控制流语句
112.
USE Sales GO -- 批处理结束标志 CREATE VIEW employee_info AS SELECT * FROM employee GO -- CREATE VIEW 语句与其他语句隔离 SELECT * FROM employee_info GO 例 9-33 创建一个视图,使用 GO 命令将 CREATE VIEW 语句与批处理中的其他语句 ( 如 USE 、 SELECT 语句等 ) 隔离。 9.3 程序控制流语句
语法格式如下: DECLARE cursor_name[ INSENSITIVE ] [ SCROLL ] CURSOR FOR select_statement [ FOR { READ ONLY | UPDATE [ OF column_name [ ,...n ] ] } ] 1. SQL-92 游标定义格式 9.4.2 声明游标
121.
表 9-13 SCROLL 的取值 9.4.2 声明游标 提取游标中的第 n 行数据 ABSULUTE n 提取游标当前位置之前或之后的第 n 行数据 (n 为正表示向后, n 为负表示向前 ) RELATIVE n 提取游标当前位置的下一行数据 NEXT 提取游标当前位置的上一行数据 PRIOR 提取游标中的最后一行数据 LAST 提取游标中的第一行数据 FIRST 含 义 SCROLL 选项
122.
例 9-34 使用 SQL-92 标准的游标声明语句声明一个游标,用于访问 Sales 数据库中的 goods 表的信息。 USE Sales GO DECLARE Goods_cursor CURSOR FOR SELECT * FROM Goods FOR READ ONLY 9.4.2 声明游标
123.
语法格式如下: DECLARE cursor_nameCURSOR [ 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 扩展游标定义格式 9.4.2 声明游标
124.
例 9-35 为 customer 表定义一个全局滚动动态游标,用于访问顾客的编号、姓名、地址、电话信息。 DECLARE cur_customer CURSOR GLOBAL SCROLL DYNAMIC FOR SELECT customer_id,customer_name,address,telphone FROM customer 9.4.2 声明游标
125.
9.4.3 使用游标1. 打开游标 游标声明之后,必须打开才能使用。打开游标的语法格式如下: OPEN {{[GLOBAL] cursor_name} | cursor_variable_name } 例如,打开例 9-35 所声明的游标操作: OPEN cur_customer 9.4 游标管理与应用
OPEN cur_customer FETCHNEXT FROM cur_customer /* 取第一个数据行 */ WHILE @@fetch_status = 0 /* 检查 @@fetch_status 是否还有数据可取 */ BEGIN FETCH NEXT FROM cur_customer END 例 9-36 打开例 9-35 中声明的游标,读取游标中的数据。 9.4.3 使用游标
129.
CLOSE 的语法格式为: CLOSE{{[ GLOBAL ] cursor_name } | cursor_variable_name } 例如,关闭例 9-35 中的游标 cur_customer 的命令: CLOSE cur_customer 游标 cur_customer 在关闭后,仍可用 OPEN 语句打开继续读取数据行。 3. 关闭游标 9.4.3 使用游标
9.4.4 游标的应用1. 用游标修改和删除表数据 定位修改游标数据的语法格式为: UPDATE table_name SET {column_name={expression | DEFAULT | NULL }[, ... n] WHERE CURRENT OF {{[GLOBAL] cursor_name} | cursor_variable_name} 删除游标数据的语法格式为: DELETE FROM table_name WHERE CURRENT OF {{[GLOBAL] cursor_name} | cursor_variable_name} 9.4 游标管理与应用
132.
例 9-37 定义游标 cur_customer ,通过 cur_customer 更新 customer 表中的 customer_name 和 linkman_name 列。 DECLARE cur_customer CURSOR FOR SELECT * FROM customer FOR UPDATE OF customer_name,linkman_name /* 该两列可更新 */ OPEN cur_customer /* 打开 cur_customer 游标 */ FETCH NEXT FROM cur_customer /* 将第一行数据放入缓冲区,以便更新操作 */ UPDATE customer SET customer_name=' 南方体育用品公司 ',linkman_name=' 李强 ' WHERE CURRENT OF cur_customer CLOSE cur_customer /* 关闭 cur_customer 游标 */ 9.4.4 游标的应用
133.
若要删除 customer 表的一行数据,则使用以下命令替换例9-37 中的 UPDATE 语句,就可以删除通过游标读入的一行数据。 DELETE FROM customer WHERE CURRENT OF cur_customer 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 9.4.4 游标的应用
140.
9.4.5 使用系统存储过程管理游标1. sp_cursor_list sp_cursor_list 显示在当前作用域内的游标及其属性 sp_cursor_list [@cursor_return=]cursor_variable_name OUTPUT, [@cursor_scope=]cursor_scope 9.4 游标管理与应用 表示 LOCAL 、 GLOBAL 游标都返回 3 表示返回所有的 GLOBAL 游标 2 表示返回所有的 LOCAL 游标 1 描 述 cursor_scope 值 表 9-15 游标作用域范围值
141.
例 9-40 声明一个键值驱动游标,并使用 sp_cursor_list 报告该游标的特性。 DECLARE employee_cur CURSOR KEYSET FOR SELECT employee_name FROM Employee WHERE employee_name LIKE ' 肖 %' OPEN employee_cur DECLARE @report CURSOR /* 声明游标 @report 存储来自 sp_cursor_list 的信息 */ /* 执行 sp_cursor_list 将信息送游标变量 @report*/ EXEC master.dbo.sp_cursor_list @cursor_return = @report OUTPUT,@cursor_scope = 2 FETCH NEXT FROM @report WHILE (@@fetch_status <> -1) BEGIN FETCH NEXT FROM @report END CLOSE @report DEALLOCATE @report GO CLOSE employee_cur DEALLOCATE employee_cur GO 9.4.5 使用系统存储过程管理游标
例 9-41 定义并打开一个全局游标,使用 sp_describe_cursor 报告游标的特性。 DECLARE employee_cur CURSOR STATIC FOR SELECT employee_name FROM employee OPEN employee_cur DECLARE @report CURSOR EXEC master.dbo.sp_describe_cursor @cursor_return = @Report OUTPUT, @cursor_source = N'global', @cursor_identity = N'employee_cur' FETCH NEXT from @report WHILE (@@FETCH_STATUS <> -1) BEGIN FETCH NEXT from @report END CLOSE @report DEALLOCATE @report GO CLOSE employee_cur DEALLOCATE employee_cur GO 9.4.5 使用系统存储过程管理游标
144.
本章小结 数据类型是学习 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 语句。