理解T-SQL: 脚本和批处理
脚本能够将相应的T-SQL命令组织起来,实现一个完整的功能目标。脚本提供了变量、分支、循环等控制语句,可以用来实现一些复杂的任务。通过组织一系列的SQL命令编成脚本和批处理,也减低了数据库管理的复杂性。
1. USE语句
没啥好讲的,功能就是设置当前的数据库。
2. 声明变量
使用declare关键字,语法非常简单:
declare @<变量名> <变量类型> [,@<变量名> <变量类型> [.. ]]
可以一次声明多个变量。变量声明后,但未赋值前,其值为NULL。
3. 给变量赋值
有两种方法,使用SET和使用select.
当知识该值是确切值或者是其它变量时,使用SET、当变量赋值基于一个查询时,使用SELECT
set
@Test
=
10
;
set
@test
=
@var1
select
@Test
=
Max
(Unitprice)
from
SalesOrderDetail;
4. 系统变量
SQL Server有30多个全局系统变量,但以下几个关键的系统变量要记住,经常用到:
@@ERROR : 返回当前连接下,最后执行T-SQL语句的错误代码,如无错误则返回0
@@FETCH_STATUS : 和FETCH配合使用,返回0表示FETCH有效,%表示超出结果集,-2表示不存在该行
@@IDENTITY : 返回最后插入的标识值,作为最后INSERT或者SELECT INTO语句的结果。
@@ROWCOUNT : 一个最有用的系统变量,返回最后语句影响的函数
@@SERVRNAME : 返回脚本正在运行的本地服务器的名字
@@TRANCOUNT : 返回活动事务的数量。
5.批处理
批处理是T-SQL语句集合的逻辑单元。 在批处理的所有语句被整合成一个执行计划。一个批处理内的所有语句要么被放在一起通过解析,要么没有一句能够执行。
为了将脚本分成多个批处理,需要使用GO语句.以下语句被分为三个批处理:
USE
AdventureWorks
DECLARE @MyVarchar varchar ( 50
) -- This DECLARE only lasts for this batch!
SELECT @MyVarchar = ‘Honey, I’’m home
’
PRINT ‘Done with first Batch
’
GO
PRINT @MyVarchar -- This generates an error since @MyVarchar --isn’t declared in this batch
PRINT ‘Done with second Batch’
GO
PRINT ‘Done with third batch’ -- Notice that this still gets executed -- even after the error
GO
对于以上,每一个批处理都会被独立执行,每个批处理的错误不会阻止其它批处理的运行(批处理2发生错误,不被执行,但批处理3照样可以执行。)
另外,GO不是一个SQL命令,它只是一个被编辑工具(SQL Server Management Studio,SQLCMD)识别的命令。
6.何时使用批处理
批处理有多种用途,但常被用在某些事情不得不放在前面发生,或者不得不和其它事情分开的脚本中。
使用以下几个命令时,必须独自成批处理,包括:
● CREATE DEFAULT
● CREATE PROCEDURE
● CREATE RULE
● CREATE TRIGGER
● CREATE VIEW
7. 使用批处理建立优先级
当需要考虑语句执行的优先顺序时,需要一个任务在另一个任务开始前,前一个任务必须被执行。优先级就需要考虑到。看一下下面的例子:
CREATE
DATABASE
Test
USE
Test
CREATE
TABLE
TestTable
(
col1 int
,
col2 int
)
以上语句不能正确执行,原因何在,是因为在USE Test时,必须需要前面一条语句"Create DataBase Test”被执行,而要让创建数据库的命令在USE TEST时被执行,必须为前面一个语句创建批处理:
CREATE
DATABASE
Test
GO
USE
Test
CREATE
TABLE
TestTable
(
col1 int
,
col2 int
)
然后,用以下语句进行验证,发现表确实被创建了:
use master;
SELECT
TABLE_CATALOG
FROM
INFORMATION_SCHEMA.TABLES
WHERE
TABLE_NAME
=
‘TestTable’;
8. 创建批处理后的执行
●可以使用sqlcmd命令来执行,一般命令格式如下:
c:\>sqlcmd –Usa –Ppasswd –i mysql.sql
sqlcmd的命令开关包括很多项,以下列出:
sqlcmd
[
{ { -U <login id> [ -P <password>
]
}
|
–E
<
可信连接
>
} ]
[
-S <服务器名> [ \<实例名>
]
]
[
-H <工作站名>
]
[
-d <数据库名>
]
[
-l <登录超时>
]
[
-t <查询超时>
]
[
-h <标题(间行数)>
]
[
-s <列分隔符>
]
[
-w <列宽>
]
[
-a <分组大小>
]
[
-e
]
[
-I
]
[
-c <批处理终止符>
]
[
-L [ c
]
]
[
-q “<query>”
]
[
-Q “<query>”
]
[
-m <error level>
]
[
-V
]
[
-W
]
[
-u
]
[
-r [ 0 | 1
]
]
[
-i <input file>
]
[
-o <output file>
]
[
-f <代码页> | i:<输入代码页> [ <, o: <输出代码页>
]
[
-k [ 1 | 2
]
]
[
-y <可变类型显示宽度>
]
[
-Y <固定类型显示宽度>
]
[
-p [ 1
]
]
[
-R
]
[
-b
]
[
-v
]
[
-A
]
[
-X [ 1
]
]
[
-x
]
[
-?
]
]
● 另外,也可心使用EXEC来执行相应的批处理
EXEC ((字符串变量)|(字面值命令字符串))
EXECUTE ((字符串变量)|(字面值命令字符串))
DECLARE
@InVar
varchar
(
50 )
DECLARE
@OutVar
varchar
(
50 )
--
Set up our string to feed into the EXEC command
SET
@InVar
=
‘
SELECT
@OutVar
=
FirstName
FROM
Person.Contact
WHERE
ContactID
=
1 ’
EXEC
(
@Invar
)
执行EXEC有许多需要留意的地方,具体可查看《SQL Server2005高级程序设计》10.4节。
9. 流控制语句
T-SQL包括的流控制语句包括:
● IF…ELSE
● GOTO
● WHILE
● WAITFOR
● TRY/CATCH
● CASE
a. IF…ELSE语句
IF…ELSE语句用得很频繁,其基本语法是:
IF
<
Boolean Expression
>
<
SQL statement
>
|
BEGIN
<
code series
>
END
[
ELSE
<SQL statement> | BEGIN <code series> END ]
注意,使用代码行时,别忘了BEGIN与END
另外,对于IF判断有一个陷阱,就是 if @var = NULL.这样子写法是不对的,因为NULL不等于任何东西,甚至也不等于NULL,应该写成:
if @var IS NULL
b. CASE语句
有不止一句方式来写CASE语句,可以同时输入表达式或布尔表达式协同工作。
第一种选择是使用一个输入表达式,同每一个WHEN子句使用的值进行比较,这种CASE称作简单CASE:
CASE
<
input expression
>
WHEN
<
when
expression
>
THEN
<
result expression
>
[
n ]
[
ELSE <result expression>
]
END
第二种情况是把每一个WHEN子句的布尔值提供给表达式,这种CASE叫作搜索CASE:
CASE
WHEN
<
Boolean expression
>
THEN
<
result expression
>
[
n ]
[ ELSE <result expression>
]
END
●● 简单CASE需要使用一个能得到布尔值的表达式,例如:
SELECT TOP
10 SalesOrderID, SalesOrderID %
10 AS ‘Last Digit’, Position
=
CASE SalesOrderID %
10
WHEN 1 THEN ‘First’
WHEN 2 THEN ‘Second’
WHEN 3 THEN ‘Third’
WHEN 4 THEN ‘Fourth’
ELSE ‘Something Else
’
END
FROM Sales.SalesOrderHeader
以上,得出的结果如下所示:
OrderID Last Digit Position
--------- ----------- --------------------
10249 9 Something Else
10251 1 First
10258 8 Something Else
10260 0 Something Else
10265 5 Something Else
10267 7 Something Else
10269 9 Something Else
10270 0 Something Else
10274 4 Fourth
10275 5 Something Else
(10 row(s) affected)
、 ●● 搜索CASE和简单CASE类似,但有两点微小的差异:
在CASE和第一个WHEN之间没有输入表达式
WHEN表达式必须同一个布尔值相比较
SELECT TOP
10 SalesOrderID %
10 AS ‘OrderLastDigit’,
ProductID % 10 AS ‘ProductLastDigit’,
“How Close ?” =
CASE
WHEN (SalesOrderID %
10 ) <
3 THEN ‘Ends
With
Less Than Three’
WHEN ProductID =
6 THEN ‘ProductID
is
6 ’
WHEN ABS
(SalesOrderID
%
10 - ProductID)
<=
1 THEN ‘Within
1 ’
ELSE
‘More Than One Apart’
END
FROM Sales.SalesOrderDetail
得到的结果如下所示:
OrderLastDigit ProductLastDigit How Close?
-------------- ---------------- -------------------
2 5 More Than One Apart
3 2 More Than One Apart
3 9 More Than One Apart
3 8 More Than One Apart
2 2 More Than One Apart
2 8 More Than One Apart
1 7 Within 1
1 0 Within 1
1 1 Within 1
0 2 Exact Match!
搜索CASE把条件放到了WHEN后面,而不是所有的WHEN共用一个条件!
C. WHILE语句
WHILE语句的语法如下所示:
WHILE < Boolean expression
>
<
sql statement
>
|
[ BEGIN
<statement block>
[BREAK ]
< sql statement >
|
<
statement block
>
[ CONTINUE ]
END ]
看一个例子,使用WHILE与WAITFOR创建一个监视进程 ,打算每天自动更新一次统计数据:
WHILE 1 =
1
BEGIN
WAITFOR TIME ‘ 01 : 00 ’
EXEC sp_updatestats
RAISERROR (‘ Statistics
Updated
for
Database
’,
1 , 1 ) WITH
LOG
END
d. WAITFOR语句
WAITFOR语句表示时间等待,语法如下:
WAITFOR
DELAY <’time’> | TIME <’time’>
DELAY参数指定等待的时间量,不能指定天数,只能指定小时,分钟,秒。最大的延迟时间是24小时,
WAITFOR DELAY ‘ 01 : 00 ‘; 等1个小时后执行下面的语句
TIME参数指定等到一天中某个特定时刻。同样也只能用24小时制:
WAITFOR TIME ‘ 01 : 00 ’; 等到今天01:00时刻执行下面的语句