uyfrjk 发表于 2018-10-23 08:30:40

29. SQL -- T-SQL 流程控制语句

  T-SQL 流程控制语句
  Transact-SQL 语言提供了一些可以用于改变语句执行顺序的命令,称为流程控制语句。流程控制语句允许用户更好地组织存储过程中的语句,方便地实现程序的功能。流程控制语句与常见的程序设计语言类似,主要包含以下几种。
  T-SQL 的流程控制语句:
  IF…ELSE
  BEGIN…END
  CASE
  WHILE…CONTINUE…BREAK
  WAITFOR
  GOTO
  RETURN
  IFELSE 语句:
  指定 Transact-SQL 语句的执行条件。如果满足条件,则在 IF 关键字及其条件之后执行 Transact-SQL语句:布尔表达式返回 TRUE。可选的 ELSE 关键字引入另一个Transact-SQL 语句,当不满足 IF 条件时就执行该语句:布尔表达式返回 FALSE。IF...ELSE 构造可用于批处理、存储过程和即时查询。当此构造用于存储过程时,通常用于测试某个参数是否存在。
  IFELSE 语句:
  IF Boolean_expression
  { sql_statement |statement_block }
  [ ELSE
  { sql_statement |statement_block } ]
  IF条件表达式>
  命令行或程序块>
  
  命令行或程序块>]
  其中条件表达式>可以是各种表达式的组合,但表达式的值必须是“真”或“假”。ELSE
  子句是可选的。IFELSE 语句用来判断当某一条件成立时执行某段程序,条件不成立时执行另一段程序。如果不使用程序块,IF 或ELSE 只能执行一条命令。IFELSE 可以嵌套使用,最多可嵌套32 级
  参数:
  Boolean_expression: 返回 TRUE 或 FALSE 的表达式。如果布尔表达式中含有SELECT 语句,则必须用括号将SELECT 语句括起来。
  {sql_statement | statement_block }:任何 Transact-SQL 语句或用语句块定义的语句分组。除非使用语句块,否则IF 或 ELSE 条件只能影响一个 Transact-SQL 语句的性能。若要定义语句块,请使用控制流关键字BEGIN 和 END可以在其他 IF 之后或在 ELSE 下面,嵌套另一个 IF 测试。嵌套级数的限制取决于可用内存
  示例:在 uspGetList 存储过程的输出中使用了IFELSE。该存储过程在创建存储过程中定义。在此示例中,该存储过程返回标价低于700 美元的自行车清单。这将导致执行第一个 PRINT 语句
  DECLARE @compareprice money,@cost money
  EXECUTEProduction.uspGetList '%Bikes%', 700,
  @compareprice OUT,
  @cost OUTPUT
  IF @cost = 50 andListPrice < 250 THEN 'Under $250'
  WHEN ListPrice >= 250 andListPrice < 1000 THEN 'Under $1000'
  ELSE 'Over $1000'
  END
  FROM Production.Product
  ORDER BY ProductNumber ;
  GO
  
  WHILE…CONTINUE…BREAK
  只要指定的条件为True 时,WHILE 语句就会重复语句或语句块。
  下面两个 Transact-SQL 语句通常和WHILE 一起使用:REAK 或 CONTINUE。
  BREAK 语句退出最内层的WHILE 循环,CONTINUE 语句则重新开始WHILE 循环。例如,如果没有其他行可以处理,程序可能执行BREAK 语句。例如,如果要继续执行代码,则可以执行CONTINUE 语句。
  如果将 SELECT 语句用作WHILE 语句的条件,则SELECT 语句必须在括号中
  语句:
  WHILE 条件表达式>
  BEGIN
  命令行或程序块>
  
  
  [命令行或程序块]
  END
  WHILE 命令在设定的条件成立时会重复执行命令行或程序块。
  CONTINUE 命令可以让程序跳过CONTINUE 命令之后的语句,回到WHILE 循环的第一行命令。
  BREAK 命令则让程序完全跳出循环,结束WHILE 命令的执行。
  WHILE 语句也可以嵌套。
  示例:
  A、在游标中使用WHILE
  下面的示例使用 WHILE 语句控制执行的提取数。
  USE AdventureWorks;
  GO
  DECLARE abc CURSOR FOR
  SELECT * FROMPurchasing.ShipMethod;
  OPEN abc;
  FETCH NEXT FROM abc
  WHILE (@@FETCH_STATUS = 0)
  FETCH NEXT FROM abc;
  CLOSE abc;
  DEALLOCATE abc;
  GO
  B. 在嵌套的 IF...ELSE 和 WHILE 中使用 BREAK 和 CONTINUE
  在以下示例中,如果产品的平均标价小于$300,则WHILE 循环将价格乘2,然后选择最高价格。如果最高价格小于或等于$500,则WHILE 循环重新开始,并再次将价格乘 2。该循环不断地将价格乘2,直到最高价格超过$500,然后退出 WHILE 循环,并输出一条消息。
  USE AdventureWorks;
  GO
  WHILE (SELECT AVG(ListPrice)FROM Production.Product) < $300
  BEGIN
  UPDATE Production.Product
  SET ListPrice = ListPrice *2
  SELECT MAX(ListPrice) FROMProduction.Product
  IF (SELECT MAX(ListPrice)FROM Production.Product) > $500
  BREAK
  ELSE
  CONTINUE
  END
  PRINT 'Too much for themarket to bear';
  C、创建一个数学运算表达式:
  DECLARE @x INT, @y INT, @c INT
  SELECT @x = 1, @y = 1
  WHILE @x < 3
  BEGIN
  PRINT @x --打印变量x 的值
  WHILE @y < 3
  BEGIN
  SELECT @c = 100*@x+ @y
  PRINT @c --打印变量c 的值
  SELECT @y = @y + 1
  END
  SELECT @x = @x + 1
  SELECT @y = 1
  END
  返回结果:
  1 101 102
  2 201 202
  WAITFOR
  在达到指定时间或时间间隔之前,或者指定语句至少修改或返回一行之前,阻止执行
  批处理、存储过程或事务.
  语法:
  WAITFOR
  {
  DELAY 'time_to_pass'
  | TIME 'time_to_execute'
  | [ ( receive_statement ) |( get_conversation_group_statement ) ]
  [ , TIMEOUT timeout ]
  }
  参数:
  DELAY:可以继续执行批处理、存储过程或事务之前必须经过的指定时段,最长可为24 小时。
  'time_to_pass ' :等待的时段。可以使用datetime 数据可接受的格式之一指定
  time_to_pass,也可以将其指定为局部变量。不能指定日期;因此,
  不允许指定datetime 值的日期部分。
  TIME:指定的运行批处理、存储过程或事务的时间。
  'time_to_execute ':WAITFOR 语句完成的时间。可以使用datetime数据可接受的格式之一指定 time_to_execute,也可以将其指定为局部变量。不能指
  定日期;因此,不允许指定datetime值的日期部分。
  receive_statement:有效的 RECEIVE语句。
  get_conversation_group_statement:有效的 GETCONVERSATION GROUP 语句
  TIMEOUT timeout:指定消息到达队列前等待的时间(以毫秒为单位)。
  示例:
  A. 使用 WAITFOR TIME
  以下示例在晚上 10:20(22:20) 执行存储过程sp_update_job
  USEmsdb;
  EXECUTEsp_add_job @job_name = 'TestJob';
  BEGIN
  WAITFORTIME '22:20';
  EXECUTEsp_update_job @job_name = 'TestJob',
  @new_name= 'UpdatedJob';
  END;
  GO
  B、使用 WAITFOR DELAY
  以下示例在两小时的延迟后执行存储过程。
  BEGIN
  WAITFORDELAY '02:00';
  EXECUTEsp_helpdb;
  END;
  GO
  C、等待1 小时2 分零3 秒后才执行SELECT 语句
  WAITFORDELAY 01:02:03
  SELECT* FROM Toys
  D、等到晚上11 点零8 分后才执行SELECT 语句
  WAITFORTIME 23:08:00
  SELECT* FROM Toys
  
  GOTO
  将执行流更改到标签处。跳过GOTO 后面的 Transact-SQL语句,并从标签位置继续处理。GOTO 语句和标签可在过程、批处理或语句块中的任何位置使用。GOTO 语句
  可嵌套使用,
  语法:
  Definethe label:
  label:
  Alterthe execution:
  GOTOlabel
  求例:
  分行打印字符1、2、3、4、5。
  DECLARE@x INT
  SELECT@x = 1
  lab_1:PRINT @x
  SELECT@x = @x+ 1
  WHILE@x < 6
  GOTO lab_1
  以下示例显示如何将GOTO 用作分支机制
  DECLARE@Counter int;
  SET @Counter = 1;
  WHILE@Counter < 10
  BEGIN
  SELECT@Counter
  SET @Counter = @Counter+ 1
  IF @Counter = 4 GOTO Branch_One --Jumps to the first branch.
  IF @Counter = 5 GOTO Branch_Two --This will never execute.
  END
  Branch_One:
  SELECT'Jumping To Branch One.'
  GOTO Branch_Three; --This will prevent Branch_Two from executing.
  Branch_Two:
  SELECT'Jumping To Branch Two.'
  Branch_Three:
  SELECT'Jumping To Branch Three.'
  RETURN
  RETURN命令用于结束当前程序的执行,返回到上一个调用它的程序或其它程序。
  在括号内可指定一个返回值
  语法:
  RETURN[ integer_expression ]
  求例:
  A. 从过程返回:
  以下示例显示如果在执行findjobs 时没有指定用户名作为参数,则RETURN将使过程
  向用户屏幕发送一条消息后退出。如果指定了用户名,则将从相应的系统表中检索此用户
  在当前数据库创建的所有对象名。
  CREATEPROCEDURE findjobs @nm sysname = NULL
  AS
  IF @nm IS NULL
  BEGIN
  PRINT'You must give a user name'
  RETURN
  END
  ELSE
  BEGIN
  SELECTo.name, o.id, o.uid
  FROM sysobjects o INNERJOIN master..sysloginsl
  ON o.uid = l.sid
  WHEREl.name= @nm
  END;
  B. 返回状态代码
  以下示例将检查指定联系人的ID 的状态。如果所在的州是Washington (WA),将返回状态代码1。在其他情况下(StateProvince的值是WA 以外的值,或者ContactID没有匹配的行),返回状态代码2。
  USE AdventureWorks;
  GO
  CREATEPROCEDURE checkstate @param varchar(11)
  AS
  IF (SELECT StateProvinceFROM Person.vAdditionalContactInfo WHERE ContactID =
  @param) = 'WA'
  RETURN1
  ELSE
  RETURN2;
  GO
  T-SQL常用SQL 语句
  语句 功能 语句 功能
  数据操作
  SELECT从数据库表中检索数据
  DELETE 从数据库表中删除数据行
  INSERT向数据库表中添加数据行
  UPDATE更新数据库表中的数据
  数据定义
  CREATE TABLE 创建一个数据库表
  CREATE PROCEDURE 创建一个存储过程
  DROP TABLE 从数据库中删除表
  DROP PROCEDURE 从数据库中删除存储过程
  ALTER TABLE 修改数据库表结构
  CREATE TRIGGER 创建一个触发器
  CREATE VIEW 创建一个视图
  DROP TRIGGER 从数据库中删除触发器
  DROP VIEW 从数据库中删除视图
  CREATE DOMAIN 创建一个数据值域
  CREATE INDEX 为数据库表创建一个索引
  ALTER DOMAIN 改变域定义
  DROP INDEX 从数据库中删除索引
  DROP DOMAIN 从数据库中删除域
  数据控制
  GRANT授予用户访问权限
  REVOKE解除用户访问权限
  DENY拒绝用户访问
  事务控制
  COMMIT结束当前事务
  SAVE RANSACTION 在事务内设置保存点
  ROLLBACK回滚当前事务
  程序化SQL
  DECLARE设定游标
  CLOSE 关闭游标
  OPEN打开一个游标
  PREPARE 为动态执行准备SQL 语句
  FETCH检索一行查询结果
  EXECUTE 动态执行SQL 语句
  
  补充:
  SQL 2005 查询过程:
  在SQLServer 2005 版本中,将一个联接查询的逻辑处理分为了10 个步骤:
  (8) SELECT (9) DISTINCT (11)
  (1) FROM
  (3) JOIN
  (2) ON
  (4) WHERE
  (5) GROUP BY
  (6) WITH {CUBE | ROLLUP}
  (7) HAVING
  (10) ORDER BY
  SQL 2008 查询过程:
  在SQLServer 2008 版本中,则对逻辑阶段的描述扩展到了所有的逻辑语句,而不仅仅是联接处理,如APPLY、PIVOT等。按这种分类方式,将逻辑步骤分成了6 部分,部分步骤中包含了子步骤。
  (5)SELECT (5-2)DISTINCT (5-3) (5-1)
  (1)FROM (1-J) JOIN ON
  |(1-A) APPLY AS
  |(1-P) PIVOT() AS
  |(1-U) UNPIVOT() AS
  (2)WHERE
  (3)GROUP BY (3-CR)WITH {CUBE | ROLLUP}
  (4)HAVING
  (6)ORDER BY
  各处理步骤流程描述:
  l 步骤1(FROM):该步骤中用于验证查询的源表,并处理表操作符。每个表操作符应用于一系列子步骤。例如,在上面用于联接的(1-J)步骤中会涉及如下的子步骤。最终这些子步骤完成后,将生成虚拟表VT1。
  (1-J1):执行left_table 和right_table两个表的交叉联接(笛卡儿乘积),生成虚拟表VT1-J1;
  (1-J2):对笛卡儿乘积应用ON 筛选器,生成虚拟表VT1-J2;
  (1-J3):如果是外部联接,会在该步骤中将被ON 筛选掉的外部行添加到VT1-J2
  中,生成VT1-J3。否则,将跳过该步骤。
  l 步骤2(WHERE):对VT1 应用WHERE 筛选器,将符合筛选条件的行插入到VT2 中。
  l 步骤3(GROUP BY):按GROUP BY子句中的列列表对VT2中的行分组,生成VT3。
  如果语句中包含WITH CUBE 或WITH ROLLUP,则将分组统计结果再次加总后插入VT3,生成VT3-RC。
  l 步骤4(HAVING):对VT3 应用HAVING 筛选器,将符合筛选条件的行插入到VT4。
  l 步骤5(SELECT):处理SELECT 子句中的元素,生成VT5。
  (5-1)计算表达式:该步骤计算SELECT 列表中的表达式,生成VT5-1;
  (5-2)DISTINCT:从VT5-1中移除重复行,生成VT5-2;
  (5-3)TOP:该步骤根据ORDER BY 子句中指定的排序规则,从VT5-2 的开始
  处筛选出指定数量或比例的行。
  l 步骤6(ORDER BY):该步骤对VT5-3 中的行按ORDERBY子句中的列列表进行排序,生成一个游标VC6

页: [1]
查看完整版本: 29. SQL -- T-SQL 流程控制语句