Transact-SQL 提供了(BEGIN...END、BREAK、GOTO、CONTINUE、IF...ELSE、WHILE、RETURN、WAITFOR)控制流关键字,用于控制 Transact-SQL 语句、语句块、用户定义函数以及存储过程的执行流。
不使用控制流语言,则各 Transact-SQL 语句按其出现的顺序分别执行。控制流语言使用与程序设计相似的构造使语句得以互相连接、关联和相互依存。
当控制流语句不能跨多个批处理、用户定义函数或存储过程。
一、 BEGIN...END
BEGIN 和 END 语句用于将多个 Transact-SQL 语句组合为一个逻辑块(即相当于C语言中{}的功能)。
例
IF (@@ERROR <> 0)
BEGIN
SET @ErrorSaveVariable = @@ERROR
PRINT 'Error encountered, ' +
CAST(@ErrorSaveVariable AS VARCHAR(10))
END
注意:
(1)BEGIN 和 END 语句块必须至少包含一条 Transact-SQL 语句。
(2)BEGIN 和 END 语句必须成对使用,任何一个均不能单独使用。BEGIN、 END 必须单独出现在一行中。
BEGIN 和 END 语句用于下列情况:
- (1)WHILE 循环需要包含语句块。
- (2)CASE 函数的元素需要包含语句块。
- (3)IF 或 ELSE 子句需要包含语句块。
二、GOTO
GOTO 语句使 Transact-SQL 批处理的执行跳至标签。不执行 GOTO 语句和标签之间的语句。使用下列语法定义标签名:
label_name:
尽量少使用 GOTO 语句。过多使用 GOTO 语句可能会使 Transact-SQL 批处理的逻辑难于理解。使用 GOTO 实现的逻辑几乎完全可以使用其他控制流语句实现。GOTO 最好用于跳出深层嵌套的控制流语句。
标签是 GOTO 的目标,它仅标识了跳转的目标。标签不隔离其前后的语句。执行标签前面语句的用户将跳过标签并执行标签后的语句。除非标签前面的语句本身是控制流语句(如 RETURN),这种情况才会发生。
示例
IF (SELECT SYSTEM_USER()) = 'payroll' GOTO calculate_salary -- Other program code would appear here. -- When the IF statement evaluates to TRUE, the statements -- between the GOTO and the calculate_salary label are -- ignored. When the IF statement evaluates to FALSE the -- statements following the GOTO are executed. calculate_salary: -- Statements to calculate a salary would appear after the label.
三、IF...ELSE
IF 语句用于条件的测试。得到的控制流取决于是否指定了可选的 ELSE 语句(总之就一句话,和其他语言的if…..else 没有什么区别)。
例、(来自MSDN)
IF (@ErrorSaveVariable <> 0) BEGIN PRINT 'Errors encountered, rolling back.' PRINT 'Last error encountered: ' + CAST(@ErrorSaveVariable AS VARCHAR(10)) ROLLBACK END ELSE BEGIN PRINT 'No Errors encountered, committing.' COMMIT END RETURN @ErrorSaveVariable
四、 WHILE...BREAK 或 CONTINUE
只要指定的条件为 True 时,WHILE 语句就会重复语句或语句块。
CONTINUE语句可以让程序跳过CONTINUE语句之后的语句,回到WHILE循环的第一行。BREAK语句则让程序完全跳出循环,结束WHILE循环(一句话,和其他语言的continue、break没有什么区别)
如果将 SELECT 语句用作 WHILE 语句的条件,则 SELECT 语句必须在括号中()。
语法格式:
WHILE<条件表达式>
BEGIN
<命令行或程序块>
[BREAK]
[CONTINUE]
[命令行或程序块]
END
例:
创建表:
CREATE TABLE PERSON_W
(ID int, char(10), char(6),工资 int,年龄 int)
循环插入记录:
DECLARE @inde int
SET @inde =10
WHILE(@inde<15)
BEGIN
INSERT INTO PERSON_W SELECT @inde,'A','ZHANG',100,20
SET @inde=@inde+1
END
查看表数据:
SELECT * FROM PERSON_W
结果:
ID 部门 员工 工资 年龄
10 A ZHANG 100 20
11 A ZHANG 100 20
12 A ZHANG 100 20
13 A ZHANG 100 20
14 A ZHANG 100 20
五、RETURN
RETURN 语句无条件终止查询、存储过程或批处理。存储过程或批处理中 RETURN 语句后面的语句都不执行。
当在存储过程中使用 RETURN 语句时,此语句可以指定返回给调用应用程序、批处理或过程的整数值。如果 RETURN 未指定值,则存储过程返回 0。
大多数存储过程按常规使用返回代码表示存储过程的成功或失败。没有发生错误时存储过程返回值 0。任何非零值表示有错误发生。
例:(来自MSDN)
USE AdventureWorks; GO -- Create a procedure that takes one input parameter -- and returns one output parameter and a return code. CREATE PROCEDURE SampleProcedure @EmployeeIDParm INT, @MaxTotal INT OUTPUT AS -- Declare and initialize a variable to hold @@ERROR. DECLARE @ErrorSave int; SET @ErrorSave = 0; -- Do a SELECT using the input parameter. SELECT c.FirstName, c.LastName, e.Title FROM HumanResources.Employee AS e JOIN Person.Contact AS c ON e.ContactID = c.ContactID WHERE EmployeeID = @EmployeeIDParm; -- Save any nonzero @@ERROR value. IF (@@ERROR <> 0) SET @ErrorSave = @@ERROR; -- Set a value in the output parameter. SELECT @MaxTotal = MAX(TotalDue) FROM Sales.SalesOrderHeader; IF (@@ERROR <> 0) SET @ErrorSave = @@ERROR; -- Returns 0 if neither SELECT statement had -- an error, otherwise returns the last error. RETURN @ErrorSave; GO
执行存储过程的 Transact-SQL 批处理或存储过程可以将返回代码检索到整数变量中:
DECLARE @ReturnStatus int; DECLARE @MaxTotalVariable int; DECLARE @MaxTotal int; EXECUTE @ReturnStatus = SampleProcedure @EmployeeIDParm = 65 ,@MaxTotal = @MaxTotalVariable OUTPUT; PRINT ' '; PRINT 'Return code = ' + CAST(@ReturnStatus AS CHAR(10)); PRINT 'Maximum Order Total = ' + CAST(@MaxTotalVariable AS CHAR(15)); GO
调用存储过程的应用程序可以将返回代码所对应的参数标记与整型变量绑定。
六、WAITFOR
WAITFOR 语句挂起批处理、存储过程或事务的执行,直到发生以下情况:
- (1)已超过指定的时间间隔。
- (2)到达一天中指定的时间。
- (3)指定的 RECEIVE 语句至少修改一行或并将其返回到 Service Broker 队列。
实际的时间延迟可能随着指定的时间而变化,并取决于服务器的活动级别。时间计数器在计划完与 WAITFOR 语句关联的线程后启动。如果服务器忙碌,则可能不会立即计划线程;因此,时间延迟可能比指定的时间要长。
WAITFOR 语句由下列子句之一指定:
- DELAY 关键字后为 time_to_pass,是指完成 WAITFOR 语句之前等待的时间。完成 WAITFOR 语句之前等待的时间最多为 24 小时。
在下面的示例中,执行SELECT
语句之前使用DELAY
关键字等待两秒钟:WAITFOR DELAY '00:00:02' SELECT EmployeeID FROM AdventureWorks.HumanResources.Employee;
- TIME 关键字后为 time_to_execute,指定 WAITFOR 语句完成所用的时间。
下面的示例使用TIME
关键字等到晚上 10 点 (22:00
) 才执行AdventureWorks
数据库检查,从而确保正确地分配并使用所有页:USE AdventureWorks; GO BEGIN WAITFOR TIME '22:00'; DBCC CHECKALLOC; END; GO
- RECEIVE 语句子句,从 Service Broker 队列检索一条或多条消息。使用 RECEIVE 语句指定 WAITFOR 时,如果当前未显示任何消息,该语句将等待消息到达队列。
- 后面带有 timeout 的 TIMEOUT 关键字将指定 Service Broker 等待消息到达队列的时间(毫秒)。可以在 RECEIVE 语句或 GET CONVERSATION GROUP 语句中指定 TIMEOUT。