流程控制语句
顺序语句
①set语句
set语句有两种用法,除了用于给局部变量赋值,还可以设定用户执行T-SQL命令时SQL Server的处理选项,一般有以下几种设定方式。
- set 选项 on:选项开关打开。
- set 选项 off:选项开关关闭。
- set 选项值:设定选项的具体值
例如,设置显示/隐藏受T-SQL语句影响的行数消息语句,其语法如下:
set nocount(on|off)
②select输出语句和print输出语句
SQL Server使用print或select输出信息。
select作为输出使用时的语法如下:
select 表达式1[,表达式2,...,表达式n]
print用于向屏幕输出信息,其语法如下:
print 表达式
- select输出会包含分隔线
- print输出类型一定要是字符类型
【示例】
1> print 'Hello World!'
2> go
Hello World!
1> select 'Hello World!'
2> go
------------
Hello World!
分支语句
①IF...ELSE语句
IF Boolean_expression
{ sql_statement | statement_block }
[ELSE
{ sql_statement | statement_block } ]
说明:
- IF...ELSE语句间不只包含一条语句时,必须使用BEGIN...END包含多条语句的语句块。
- 语句块的关键字BEGIN、END必须成对出现,允许嵌套,并且BEGIN...END之间至少包含一条SQL语句。
- IF...ELSE可以嵌套使用
【示例】
DECLARE @Number int;
SET @Number = 50;
IF @Number > 100
PRINT 'The number is large.';
ELSE
BEGIN
IF @Number < 10
PRINT 'The number is small.';
ELSE
PRINT 'The number is medium.';
END ;
GO
②CASE函数
CASE是计算条件列表,并返回多个可能的结果表达式之一。
CASE 表达式有两种格式:
- CASE 简单表达式,它通过将表达式与一组简单的表达式进行比较来确定结果。
- CASE 搜索表达式,它通过计算一组布尔表达式来确定结果。
这两种格式都支持可选的 ELSE 参数。
CASE 可用于允许使用有效表达式的任意语句或子句。 例如,可以在 SELECT、UPDATE、DELETE 和 SET 等语句以及 select_list、IN、WHERE、ORDER BY 和 HAVING 等子句中使用 CASE。
CASE语法:
--简单Case函数
CASE input_expression
WHEN when_expression THEN result_expression [ ...n ]
[ ELSE else_result_expression ]
END
--Case搜索函数
CASE
WHEN Boolean_expression THEN result_expression [ ...n ]
[ ELSE else_result_expression ]
END
【返回类型】从的类型集中返回优先级高的类型result_expressions和可选else_result_expression。
CASE 表达式不能用于控制 Transact-SQL 语句、语句块、用户定义函数以及存储过程的执行流。能控制的只有IF..ELSE、WHILE这样的控制流语言。
【示例】
A. 使用带有 CASE 简单表达式的 SELECT 语句
SELECT ProductNumber, Category =
CASE ProductLine
WHEN 'R' THEN 'Road'
WHEN 'M' THEN 'Mountain'
WHEN 'T' THEN 'Touring'
WHEN 'S' THEN 'Other sale items'
ELSE 'Not for sale'
END,
Name
FROM Production.Product
ORDER BY ProductNumber;
GO
B. 使用带有 CASE 搜索表达式的 SELECT 语句
在 SELECT 语句中,CASE 搜索表达式允许根据比较值替换结果集中的值。 下面的示例根据产品的价格范围将标价显示为文本注释。
SELECT ProductNumber, Name, "Price Range" =
CASE
WHEN ListPrice = 0 THEN 'Mfg item - not for resale'
WHEN ListPrice < 50 THEN 'Under $50'
WHEN ListPrice >= 50 and ListPrice < 250 THEN 'Under $250'
WHEN ListPrice >= 250 and ListPrice < 1000 THEN 'Under $1000'
ELSE 'Over $1000'
END
FROM Production.Product
ORDER BY ProductNumber ;
GO
C. 在 ORDER BY 子句中使用 CASE
下面的示例在 ORDER BY 子句中使用 CASE 表达式,以根据给定的列值确定行的排序顺序。
SELECT BusinessEntityID, SalariedFlag
FROM HumanResources.Employee
ORDER BY CASE SalariedFlag WHEN 1 THEN BusinessEntityID END DESC
,CASE WHEN SalariedFlag = 0 THEN BusinessEntityID END;
GO
D. 在 SET 语句中使用 CASE
SET @ContactType =
CASE
-- Check for employee
WHEN EXISTS(SELECT * FROM HumanResources.Employee AS e
WHERE e.BusinessEntityID = @BusinessEntityID)
THEN 'Employee'
-- Check for vendor
WHEN EXISTS(SELECT * FROM Person.BusinessEntityContact AS bec
WHERE bec.BusinessEntityID = @BusinessEntityID)
THEN 'Vendor'
-- Check for store
WHEN EXISTS(SELECT * FROM Purchasing.Vendor AS v
WHERE v.BusinessEntityID = @BusinessEntityID)
THEN 'Store Contact'
-- Check for individual consumer
WHEN EXISTS(SELECT * FROM Sales.Customer AS c
WHERE c.PersonID = @BusinessEntityID)
THEN 'Consumer'
END;
循环语句
T-SQL中的循环语句只有while一种语法形式,while语句还可以和break、continue语句一起使用。其结构如下所示:
WHILE Boolean_expression
{ sql_statement | statement_block | BREAK | CONTINUE }
- WHILE语句可以嵌套
- WHILE语句间不只包含一条语句时,必须使用BEGIN...END包含多条语句的语句块。
- CONTINUE:使 WHILE 循环重新开始执行,忽略 CONTINUE 关键字后面的任何语句。
- BREAK:导致从最内层的 WHILE 循环中退出。 执行标记的末尾循环中,在结束关键字后显示的任何语句。
- 如果嵌套了两个或多个 WHILE 循环,则内层的 BREAK 将退出到下一个外层循环。 将首先运行内层循环结束之后的所有语句,然后重新开始下一个外层循环。
【示例】
USE AdventureWorks2012;
GO
WHILE (SELECT AVG(ListPrice) FROM Production.Product) < $300
BEGIN
UPDATE Production.Product SET ListPrice = ListPrice * 2
SELECT MAX(ListPrice) FROM Production.Product
IF (SELECT MAX(ListPrice) FROM Production.Product) > $500
BREAK
ELSE
CONTINUE
END
PRINT 'Too much for the market to bear';
其他控制语句
①WAITFOR语句
waitfor语句称为延时语句,它的功能暂停程序执行,直到所设定的等待时间已过或所设定的时间已到才继续玩下执行。。其语法如下:
WAITFOR
{
DELAY 'time_to_pass'
| TIME 'time_to_execute'
| [ ( receive_statement ) | ( get_conversation_group_statement ) ]
[ , TIMEOUT timeout ]
}
- DELAY:用来设定等待时间,最多可达24小时。
- time_to_pass:等待的时段。 time_to_pass可接受格式之一指定datetime数据,也可以指定为本地变量。
- TIME:指定的运行批处理、存储过程或事务的时间。
- time_to_execute:WAITFOR 语句完成的时间。 time_to_execute可接受格式之一指定datetime数据,也可以指定为本地变量。
【示例】
A. 使用 WAITFOR TIME
下面的示例在晚上 10:20 在 msdb 数据库中执行 sp_update_job 存储过程。
EXECUTE sp_add_job @job_name = 'TestJob';
BEGIN
WAITFOR TIME '22:20';
EXECUTE sp_update_job @job_name = 'TestJob',
@new_name = 'UpdatedJob';
END;
GO
B. 使用 WAITFOR DELAY
以下示例在两小时的延迟后执行存储过程。
BEGIN
WAITFOR DELAY '02:00';
EXECUTE sp_helpdb;
END;
GO
C. 在 WAITFOR DELAY 中使用局部变量
以下示例显示如何对 WAITFOR DELAY 选项使用局部变量。 将创建一个存储过程,该过程将等待可变的时间段,然后将经过的小时、分钟和秒数信息返回给用户。
CREATE PROCEDURE dbo.TimeDelay_hh_mm_ss
(@DelayLength char(8)= '00:00:00')
AS
DECLARE @ReturnInfo varchar(255)
IF ISDATE('2000-01-01 ' + @DelayLength + '.000') = 0
BEGIN
SELECT @ReturnInfo = 'Invalid time ' + @DelayLength
+ ',hh:mm:ss, submitted.';
PRINT @ReturnInfo
RETURN(1)
END
BEGIN
WAITFOR DELAY @DelayLength
SELECT @ReturnInfo = 'A total time of ' + @DelayLength + ',
hh:mm:ss, has elapsed! Your time is up.'
PRINT @ReturnInfo;
END;
GO
EXEC TimeDelay_hh_mm_ss '00:00:10';
GO
②RETURN语句
从查询或过程中无条件退出。 RETURN 的执行是即时且完全的,可在任何时候用于从过程、批处理或语句块中退出。 RETURN 之后的语句是不执行的。其语法如下:
RETURN [<整形表达式>]
错误处理语句
a. 简单的异常处理
在T-SQL程序中,把可能出现异常的程序语句放置在try部分(begin try...end tey),错误处理语句放置在catch部分(begin catch...end catch),如果在try部分未发生错误,则catch部分的语句会被忽略,如果try部分的语句发生了异常,则程序控制转移至相应的catch部分。如果try..catch捕获了错误并进行了处理,对于调用者来说,相当于没发生错误。
如下面语句在try部分不会发生错误,catch部分的语句也不会被执行:
begin try
print 10/2;
print 'No error';
end try
begin catch
print 'Error!Divided by zero.'
end catch
b. 预定义异常
在一般T-SQL程序设计中,编程者应该在catch部分分析错误原因,然后给出相应提示信息或其他处理语句。
catch部分捕获到的错误以错误号来标识,编程者通过调用error-numer()函数得到捕获到的错误号,然后根据错误号给出相关错误提示信息,或者调用error-message()函数显示系统预先定义的错误信息,SQL Server的所有预定以错误号及对应错误信息可以通过查询sys.message得到。另外,SQL Server不支持用户自定义异常。
下面示例说明try...catch的用法。创建表t,用于测试:
1> create table t
2> (
3> a int not null,
4> b int not null,
5> c char(4),
6> constraint pk_t primary key(a),
7> constraint ck_b check(b>100)
8> )
然后执行下面程序段:
begin try
insert into t values(1,170,'a');
end try
begin catch
if error_number() = 2627
begin
print 'Handling PK violation...';
end
else if error_number() = 547
begin
print 'Handling CHECK/FK constraint violation...';
end
else if error_number() = 515
begin
print 'Handling NULL violation...';
end
else if error_number() = 245
begin
print 'Handling conversion error...';
end
else
begin
print 'Handling unknow error...';
end
-- 输出错误号
print 'Error Number:'+cast(error_number() as varchar(10));
-- 输出错误信息
print 'Error Message:'+error_message();
print 'Error Severity:'+cast(error_severity() as varchar(10));
print 'Error State:'+cast(error_state() as varchar(10));
print 'Error Line:'+cast(error_line() as varchar(10));
print 'Error Proc:'+coalesce(error_procedure(),'Not within proc');
end catch
如果第二次执行上面的语句,则会因为主键存在重复值而给出以下错误信息:
Handling PK violation...
Error Number:2627
Error Message:违反了 PRIMARY KEY 约束 'pk_t'。不能在对象 'dbo.t' 中插入重复键。
Error Severity:14
Error State:1
Error Line:2
Error Proc:Not within proc
如果把添加记录的insert语句改为:
insert into t values(2,10,'a');
修改后,重新执行上述程序段,则违反了b字段上的check约束,会给出以下错误信息:
Handling CHECK/FK constraint violation...
Error Number:547
Error Message:INSERT 语句与 CHECK 约束"ck_b"冲突。该冲突发生于数据库"master", 表"dbo.t", column 'b'。
Error Severity:16
Error State:0
Error Line:2
Error Proc:Not within proc
c. 使用存储过程处理异常
如果要使得错误处理的代码可以重用,则可以把上述catch的内容创建为存储过程,以后即可在T-SQL代码中直接调用。
创建存储过程如下:
create procedure dbo.err_message
as
if error_number() = 2627
begin
print 'Handling PK violation...';
end
else if error_number() = 547
begin
print 'Handling CHECK/FK constraint violation...';
end
else if error_number() = 515
begin
print 'Handling NULL violation...';
end
else if error_number() = 245
begin
print 'Handling conversion error...';
end
else
begin
print 'Handling unknow error...';
end
-- 输出错误号
print 'Error Number:'+cast(error_number() as varchar(10));
-- 输出错误信息
print 'Error Message:'+error_message();
print 'Error Severity:'+cast(error_severity() as varchar(10));
print 'Error State:'+cast(error_state() as varchar(10));
print 'Error Line:'+cast(error_line() as varchar(10));
print 'Error Proc:'+coalesce(error_procedure(),'Not within proc');
在T-SQL程序段中调用上述存储过程:
begin try
insert into t values(2,10,'a');
end try
begin catch
exec err_message;
end catch