一.变量

变量用于临时保存数据值,以供在声明它们的同一批处理语句中引用。例如,以下代码先声明一个数据类型为INT的变量@i,再将它赋值为10;

DECLARE @i as INT;
SET @i = ;

SQL SERVER 2008新增加了对在同一语句中同时声明和初始化变量的支持,如下所示:

DECLARE @i as INT = ;

可以使用一个DECLARE语句同时声明多个变量,但是SET语句只能对一个变量进行操作,所以如果需要把值赋值给多个变量,就必须使用多个SET语句。当从同一行取出多个列的值时,这可能会带来一些不必要的开销。

DECLARE @firstname AS NVARCHAR(), @lastname AS NVARCHAR();

SET @firstname = (SELECT firstname
FROM HR.Employees
WHERE empid = );
SET @lastname = (SELECT lastname
FROM HR.Employees
WHERE empid = ); SELECT @firstname AS firstname, @lastname AS lastname;

SQL SERVER 还支持一种非标准的赋值SELECT语句,允许在单独的语句中既查询数据,也把从同一行中获得的多个值分给给多个变量,以下是这种用法的一个例子:

DECLARE @firstname AS NVARCHAR(), @lastname AS NVARCHAR();

SELECT @firstname = firstname,@lastname = lastname from HR.Employees where empid = ;

SELECT @firstname AS firstname, @lastname AS lastname;

当满足条件的查询结果只有一行时,赋值SELECT语句的行为和我们预料的一样。但是,如果查询返回多个满足条件的结果行时,这段代码也不会失败,都会进行赋值,当访问每一行时,就会用当前行的值覆盖掉变量的原有值。当赋值SELECT语句完成时,变量中保存的值是SQL SERVER随机访问到的最后一行中的值。SET语句比赋值SELECT语句更安全,因为它要求使用标题子查询来从表中提取数据。

二.批处理

批处理是从客户端应用程序发送到SQL SERVER的一组单条或多条TSQL语句,SQL SERVER将批处理语句作为单个可执行的单元。SSMS工具提供了一个客户端命令GO,可以发出一批TSQL语句结束的信号,注意,GO命令是客户端工具的命令,而不是TSQL服务器的命令。

1.批处理是语句分析的单元

批处理是作为一个单元而进行分析和执行的一组命令,如果分析成功,SQL SERVER接着就会尝试执行处理,例如,以下代码包含3个批处理,其中第二个存在语法错误。因为第二个批处理存在语法错误,所以整个批处理不会提交到SQL SERVER执行,而第一个和第三个批处理能够通过语法检查,因而可以提交到SQL SERVER执行。

2.批处理和变量

变量是属于定义它们的批处理的局部变量,如果试图引用在其他批处理中定义的变量,SQL SERVER引擎就会报告引用的变量还没有定义。

3.不能在同一批处理中编译的语句

下列语句不能在同一批处理中和其他语句同时编译:CREATE DEFAULT、CREATE FUNCTION、CREATE PROCEDURE、CREATE RULE、CREATE SCHEMA、CREATE TRIGGER及CREATE VIEW。

为了避开这个问题,可以在IF语句之后添加一个GO命令,从而把IF和CREATE VIEW语句分隔到不同的批处理中。

4.批处理是语句解析的单元

批处理是语句解析的单元,这意味着检查数据对象和列是否存在,是在批处理上进行的。当设计批处理的边界时,应该牢记这一事实。如果对数据对象的架构定义了修改,并试图在同一批处理中对该对象进行处理,那么SQL SERVER在解析时还不知道架构发生了变化,因而无法执行数据处理语句,报告解析错误。

当解析SELECT语句时,T1表还只有一列,对col2列的引用将导致错误,避免这种问题的最佳实践就是把DDL语句和DML语句分隔到不同的批处理中。

5.GO n选项

SQL SERVER 2005对GO命令这个客户端工具进行了增强,让它可以支持一个正整数参数,表示GO之前的批处理将执行指定的次数。

三.流程控制元素

1.IF ELSE流程控制元素

IF ELSE元素用于根据条件来控制代码的执行流程。如果条件取值为True,则执行指定的语句或语句块;如果取值为False或Unknown,则执行指定的另一语句或语句块(可选)。

以下代码检查今天是否是一年的最后一天:

-- The IF ... ELSE Flow Element
IF YEAR(CURRENT_TIMESTAMP) <> YEAR(DATEADD(day, , CURRENT_TIMESTAMP))
PRINT 'Today is the last day of the year.'
ELSE
PRINT 'Today is not the last day of the year.'
GO

如果需要在IF或ELSE部分运行多条语句,则可以使用语句块。语句块的边界是用一对BEGIN和END关键字标识的。

-- The IF ... ELSE Flow Element
IF YEAR(CURRENT_TIMESTAMP) <> YEAR(DATEADD(day, , CURRENT_TIMESTAMP))
BEGIN
DECLARE @msg as varchar() = 'Today is the last day of the year.';
PRINT @msg;
END
ELSE
BEGIN
DECLARE @msg2 as varchar() = 'Today is not the last day of the year.';
PRINT @msg;
END GO

2.WHILE流程控制元素

TSQL提供的WHILE流程控制元素可以用于循环执行代码。当在WHILE关键字后指定的条件取值为True时,WHILE元素可以重复执行一条语句或语句块,当指定的条件或False或Unknown时,循环将会终止。可以使用Break命令退出当前循环,继续执行循环体之后的语句,也可使用CONTINUE命令跳过当前循环的后续处理,继续进行下一次循环。

-- The WHILE Flow Element
DECLARE @i AS INT;
SET @i = ;
WHILE @i <=
BEGIN
PRINT @i;
SET @i = @i + ;
END;
GO

四.临时表

有时需要把数据临时保存在表中,而且在某些情况下,你可能并不想使用永久性的表。例如,假设你需要让数据只对当前会话可见,或者甚至只对当前批处理可见。SQL Server支持三种类型的临时表:局部临时表、全局临时表及表变量。

1.局部临时表

要创建局部临时表,只需要在命名时以单个数字符号(#)作为前缀。局部临时表只对创建它的会话在创建级和调用堆栈内部级是可见的。当创建级例程退出调用堆栈,SQL Server就会自动删除相应的临时表。假设一个存储过程Proc1调用了另一个存储过程Proc2.而Proc2又调用了另一个Proc3,Proc3又调用了Proc4。Proc2在调用Proc3之前创建了一个临时表#T1,这时表#T1对Proc2(创建级)、Proc3以及Proc4(调用堆栈)是可见的,而对Proc1是不可见的。当Proc2完成时,SQL Server就会自动删除这个表。

使用临时表的一个明显场合是当你的处理需要把中间结果临时保存起来,以供以后查询这些临时数据。另一种场合是需要多次访问某个开销昂贵的处理结果。以下是使用临时表的一个示例。

USE TSQLFundamentals2008;

IF OBJECT_ID('tempdb.dbo.#MyOrderTotalsByYear') IS NOT NULL
DROP TABLE dbo.#MyOrderTotalsByYear;
GO SELECT
YEAR(O.orderdate) AS orderyear,
SUM(OD.qty) AS qty
INTO dbo.#MyOrderTotalsByYear
FROM Sales.Orders AS O
JOIN Sales.OrderDetails AS OD
ON OD.orderid = O.orderid
GROUP BY YEAR(orderdate);

2.全局临时表

如果创建的是全局临时表,则它对其他所有会话都是可见的。当创建临时表的会话断开数据库联接,并且也没有其他活动在引用全局临时表时,SQL Server会自动删除相应的全局临时表。要创建全局临时表,只需要在命名时用两个数字符号(##)作为前缀,如##T1。使用方式与局部临时表类似。

3.表变量

和使用局部临时表一样,表变量在tempdb数据库中也有对应的表作为其物理表示,而不是像通常所理解的那样,以为表变量只在内存中存在。和局部临时表类似,表变量的访问范围更有限,它只对当前批处理可见,表变量对调用堆栈中当前批处理的内部批处理是不可见的,对会话中随后的批处理也是不可见的。使用示例:

DECLARE @MyOrderTotalsByYear TABLE
(
orderyear INT NOT NULL PRIMARY KEY,
qty INT NOT NULL
); INSERT INTO @MyOrderTotalsByYear(orderyear, qty)
SELECT
YEAR(O.orderdate) AS orderyear,
SUM(OD.qty) AS qty
FROM Sales.Orders AS O
JOIN Sales.OrderDetails AS OD
ON OD.orderid = O.orderid
GROUP BY YEAR(orderdate);

4.表类型

SQL Server2008引用了对表类型的支持,通过创建表类型,可以把表的定义保存到数据库中,以后在定义表变量、存储过程和用户定义的函数的输入参数时,可以将表类型作为 表的定义而重用。

IF TYPE_ID('dbo.OrderTotalsByYear') IS NOT NULL
DROP TYPE dbo.OrderTotalsByYear; CREATE TYPE dbo.OrderTotalsByYear AS TABLE
(
orderyear INT NOT NULL PRIMARY KEY,
qty INT NOT NULL
);
GO

五.动态SQL

SQL Server允许用字符串来动态构造TSQL代码的一个批处理,接着再执行这个批处理,这个运通称为动态SQL.SQL Server提供了两种执行动态SQL的方法:使得EXEC命令和使用sp_executesql存储过程。

1.EXEC命令

EXEC接受一个字符串作为在圆括号中输入的参数,执行字符串中包含的批处理代码。示例如下:

DECLARE @sql as varchar() = 'select firstname,lastname from HR.Employees';
EXEC(@sql);

2.sp_executesql存储过程

从sp_executesql的调用接口来说,使用这个存储过程更安全和更灵活,因为它支持输入和输出参数。正因为在动态SQL代码中可以使用输入和输出参数,这样就有助于写出更安全和更有效的代码。从安全性的角度来说,在代码中出现的参数并不是代码的一部分,而只是表达式中的运算对象,所以,通过使用参数,可以不必受SQL注入的困扰了。

sp_executesql存储过程有两个输入参数和一个参数赋值部分。在第一个参数@stmt中,需要指定包含想要运行的批处理代码的Unicode字符串。第二个参数@params是一个Unicode字符串,包含@stmt中所有输入和输出参数的声明。接着为输入和输出参数指定取值,各参数之间用逗号分隔。

SQL SERVER技术内幕之10 可编程对象的更多相关文章

  1. SQL SERVER技术内幕之10 事务并发

    1.事务 1.1事务的定义 事务是作为单个工作单元而执行的一系列操作.定义事务边界有显式和隐式两种.显式事务的定义以BEGIN TRAN作为开始,以COMMIT TRAN提交事务,以ROLLBACK ...

  2. SQL Server技术内幕笔记合集

    SQL Server技术内幕笔记合集 发这一篇文章主要是方便大家找到我的笔记入口,方便大家o(∩_∩)o Microsoft SQL Server 6.5 技术内幕 笔记http://www.cnbl ...

  3. SQL SERVER技术内幕之6 集合查询

    1.定义 集合运算会对两个输入查询的结果集进行逐行比较,根据比较结果和所使用的集合运算来确定某一行是否应该包含在集合运算的结果中.因为集合运算是针对集合之间进行的计算,所以集合运算涉及的两个查询不能包 ...

  4. SQL SERVER技术内幕之8 分组集

    分组集就是分组(GROUP BY子句)使用的一组属性,在传统的SQL中,一个聚合查询只能定义一个分组集: 假设现在不想生成4个单独的结果集,而是希望生成一个统一的结果集,其中包含所有4个分组集的聚合 ...

  5. SQL SERVER技术内幕之5 表表达式

    表表达式是一种命名的查询表达式,代表一个有效的关系表.可以像其他表一样,在数据处理语句中使用表表达式.SQL Server支持4种类型的表表达式:派生表(derived table).公用表表达式(C ...

  6. SQL SERVER技术内幕之3 联接查询

    JOIN表运算符对两个输入表进行操作.联接有三种基本类型:交叉联接.内联接和外联接.这三种联接的区别是它们采用的逻辑查询处理步骤各不相同,每种联接都有一套不同的步骤.交叉联接只有一个步骤----笛卡尔 ...

  7. SQL SERVER技术内幕之7 透视与逆透视

    1.透视转换 透视数据(pivoting)是一种把数据从行的状态旋转为列的状态的处理,在这个过程中可能须要对值进行聚合. 每个透视转换将涉及三个逻辑处理阶段,每个阶段都有相关的元素:分组阶段处理相关的 ...

  8. SQL SERVER技术内幕之4 子查询

    最外层查询的结果集会返回给调用者,称为外部查询.内部查询的结果是供外部查询使用的,也称为子查询.子查询可以分成独立子查询和相关子查询两类.独立子查询不依赖于它所属的外部查询,而相关子查询则须依赖它所属 ...

  9. SQL Server进阶(十一)可编程对象——变量、 批、流元素、 游标

    变量 --------------------------------------------------------------------- -- Variables -------------- ...

随机推荐

  1. tcp/ip五层协议

    TCP/IP协议不是TCP和IP这两个协议的合称,而是指因特网整个TCP/IP协议族.互联网协议(Internet Protocol Suite)是一个网络通信模型,以及一整个网络传输协议家族,为互联 ...

  2. 武汉Uber优步司机奖励政策(8月31日~9月6日)

    ·奖励前提 *必须满足当周平均评分4.7星及以上,且当周接单率70%及以上,当周在线5小时且完成5单,才有资格获得奖励 * 各组别必须满足当周要求的成单率才有资格获得奖励,成单率由当周 滴滴快车单单2 ...

  3. SpringBoot-01:什么是SpringBoot?

    ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- SpringBoot: Spring Boot可以轻松创建独立的,生产级的基于Spring的应用程序,您可以“ ...

  4. CentOS6.5进不去系统,修复

    今天进系统出现问题了,然后在网上搜索了一下解决方案解决了,把解决方法记录下来,方便以后查阅. 输入root密码 #mount | grep "on /" //得到root用户所在分 ...

  5. linux-flock文件锁之实际运用

    vi test.sh #! /bin/bash echo "Hello World" touch test.lock #随便命名 [root@localhost ~]# flock ...

  6. java中的比较:instanceof、equals(hashcode)、==

    import javassist.expr.Instanceof; class Person{ String s; Person(String s){ this.s=s; } } class Man ...

  7. Linux命令应用大词典-第7章 字符串、文件和命令查找

    7.1 grep:字符串.文件和命令的查找 7.2 egrep:在文件或标准输入中查找模式 7.3 fgrep:在每个文件或是标准输入中查找模式 7.4 find:列出文件系统内符合条件的文件 7.5 ...

  8. C 进制 类型说明符 位运算 char类型

    一 进制 1. 什么是进制 是一种计数的方式 数值的表示形式 2. 二进制 1> 特点: 只有0和1 逢2进1 2> 书写格式: 0b或者0B开头 3> %d 以带符号的十进制形式输 ...

  9. LabVIEW初篇---前言

    最早接触labview,是研二的时候,2007年,当时为了补贴家用,改善生活.自己拿着本科毕业证去找工作,去一个企业面试,当时,面试的主考官,问了会什么吗,比如PLC.单片机啥的?那时候的自己,基本上 ...

  10. netty in action 笔记 二

    netty的数据容器 网络数据的基本单位大多为字节,Java NIO 提供了ByteBuffer 作为它的字节容器,但使用起来过于复杂和繁琐.在Netty中, ByteBuffer 替代品是ByteB ...