SQL 高级用法

来源:互联网 发布:淘宝网上开店发货步骤 编辑:程序博客网 时间:2024/05/19 05:01

 1,临时表

(1)建立:create table #表名(字段名 类型,字段名2 类型2。。。。) 手动删除:drop table #表名

每一个用户都可以放心地插入、更新、删除表中的数据而不必担心其它的用户使该表中的数据失效,当用户退出sql时该表可以自动删除,

另一种建立方法:create table tempdb..tablename(field1 datatype,field2 datatype....)

(2)本例给出一临时表的最通常用法:在复合查询中存贮查询的结果为之后的查询使用。

选出所有的居住在nashville的艺术家的记录信息:

方法一:create table #temp_info(name char(30),homebase char(40),style char(20),artist_id int)

insert #temp_info select * from artists where homebase='nashville'

select recordings.* from recordings,artists where recordings.artist_id=#temp_info.artist_id

方法二:select artists.* from artists,recordings where artists.homebase='nashville'

3.事务控制或事务处理
它是指关系数据库系统执行数据库事务的二郎腿,事务是指在逻辑上必须完成的一命令序列的单位,单元工作期是指事务的开始和结束时期.如果在事务中产生的错误,那么整个过程可以根据需要被终止,如果每一件事都是正确的,那么结果将会被保存到数据库中.
主要目的是避免多用户同一时间(分,秒)操作数据库时,一方修改或另一方查询,将看到不正确的结果.事务处理就能避免此种情况.它能保证数据不被修改
如:begin transaction aaaa  // 建立事务处理名称aaaa
if not exists(select *from 单元号 where 楼牌号id=5)
begin
begin transaction                     //事务处理开始
insert 单元号 values(28,'一单元',5)
end
else
rollback transaction  //回滚事务处理 相当于撤销命令

if exists(select * from 单元号 where 楼牌号id=5)
begin
begin transaction
select * from 楼牌号,单元号 where 楼牌号.id=单元号.楼牌号id
end
else
rollback transaction
if exists (select * from 单元号 where 楼牌号id=6)
commit transaction   //结束事务处理,和begin transaction配对使用
else
rollback transaction
go
 

存储过程的编写经验和优化

    一、适合读者对象:数据库开发程序员,数据库的数据量很多,涉及到对SP(存储过程)的优化的项目开发人员,对数据库有浓厚兴趣的人。

  二、介绍:在数据库的开发过程中,经常会遇到复杂的业务逻辑和对数据库的操作,这个时候就会用SP来封装数据库操作。如果项目的SP较多,书写又没有一定的规范,将会影响以后的系统维护困难和大SP逻辑的难以理解,另外如果数据库的数据量大或者项目对SP的性能要求很,就会遇到优化的问题,否则速度有可能很慢,经过亲身经验,一个经过优化过的SP要比一个性能差的SP的效率甚至高几百倍。

  三、内容:

  1、开发人员如果用到其他库的Table或View,务必在当前库中建立View来实现跨库操作,最好不要直接使用“databse.dbo.table_name”,因为sp_depends不能显示出该SP所使用的跨库table或view,不方便校验。

  2、开发人员在提交SP前,必须已经使用set showplan on分析过查询计划,做过自身的查询优化检查。

  3、高程序运行效率,优化应用程序,在SP编写过程中应该注意以下几点:

  a)SQL的使用规范:

  i. 尽量避免大事务操作,慎用holdlock子句,提高系统并发能力。

  ii. 尽量避免反复访问同一张或几张表,尤其是数据量较大的表,可以考虑先根据条件提取数据到临时表中,然后再做连接。

  iii. 尽量避免使用游标,因为游标的效率较差,如果游标操作的数据超过1万行,那么就应该改写;如果使用了游标,就要尽量避免在游标循环中再进行表连接的操作。

  iv. 注意where字句写法,必须考虑语句顺序,应该根据索引顺序、范围大小来确定条件子句的前后顺序,尽可能的让字段顺序与索引顺序相一致,范围从大到小。

  v. 不要在where子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用索引。

  vi. 尽量使用exists代替select count(1)来判断是否存在记录,count函数只有在统计表中所有行数时使用,而且count(1)比count(*)更有效率。

  vii. 尽量使用“>=”,不要使用“>”。

  viii. 注意一些or子句和union子句之间的替换

  ix. 注意表之间连接的数据类型,避免不同类型数据之间的连接。

  x. 注意存储过程中参数和数据类型的关系。

  xi. 注意insert、update操作的数据量,防止与其他应用冲突。如果数据量超过200个数据页面(400k),那么系统将会进行锁升级,页级锁会升级成表级锁。

  b)索引的使用规范:

  i. 索引的创建要与应用结合考虑,建议大的OLTP表不要超过6个索引。

  ii. 尽可能的使用索引字段作为查询条件,尤其是聚簇索引,必要时可以通过index index_name来强制指定索引

  iii. 避免对大表查询时进行table scan,必要时考虑新建索引。

  iv. 在使用索引字段作为条件时,如果该索引是联合索引,那么必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引,否则该索引将不会被使用。

  v. 要注意索引的维护,周期性重建索引,重新编译存储过程。

  c)tempdb的使用规范:

  i. 尽量避免使用distinct、order by、group by、having、join、cumpute,因为这些语句会加重tempdb的负担。

  ii. 避免频繁创建和删除临时表,减少系统表资源的消耗。

  iii. 在新建临时表时,如果一次性插入数据量很大,那么可以使用select into代替create table,避免log,提高速度;如果数据量不大,为了缓和系统表的资源,建议先create table,然后insert。

  iv. 如果临时表的数据量较大,需要建立索引,那么应该将创建临时表和建立索引的过程放在单独一个子存储过程中,这样才能保证系统能够很好的使用到该临时表的索引。

  v. 如果使用到了临时表,在存储过程的最后务必将所有的临时表显式删除,先truncate table,然后drop table,这样可以避免系统表的较长时间锁定。

  vi. 慎用大的临时表与其他大表的连接查询和修改,减低系统表负担,因为这种操作会在一条语句中多次使用tempdb的系统表。

  d)合理的算法使用:

  根据上面已提到的SQL优化技术和ASE Tuning手册中的SQL优化内容,结合实际应用,采用多种算法进行比较,以获得消耗资源最少、效率最高的方法。具体可用ASE调优命令:set statistics io on, set statistics time on , set showplan on 等。
存储过程应该是一组经过压缩处理的经常使用的一组命令(如交叉表的查询,更新和插入操作).存储过程允许程序简单地将该过程作为一个函数来调用而不是重复地执行过程内部的语句.

SQL语句导入导出大全

/******* 导出到excel 
EXEC master..xp_cmdshell ’bcp SettleDB.dbo.shanghu out c:/temp1.xls -c -q -S"GNETDATA/GNETDATA" -U"sa" -P""’

/*********** 导入Excel 
SELECT * 
FROM OpenDataSource( ’Microsoft.Jet.OLEDB.4.0’, 
’Data Source="c:/test.xls";User ID=Admin;Password=;Extended properties=Excel 5.0’)...xactions


SELECT cast(cast(科目编号 as numeric(10,2)) as nvarchar(255))+’ ’ 转换后的别名 
FROM OpenDataSource( ’Microsoft.Jet.OLEDB.4.0’, 
’Data Source="c:/test.xls";User ID=Admin;Password=;Extended properties=Excel 5.0’)...xactions

/** 导入文本文件 
EXEC master..xp_cmdshell ’bcp "dbname..tablename" in c:/DT.txt -c -Sservername -Usa -Ppassword’

/** 导出文本文件 
EXEC master..xp_cmdshell ’bcp "dbname..tablename" out c:/DT.txt -c -Sservername -Usa -Ppassword’ 
或 
EXEC master..xp_cmdshell ’bcp "Select * from dbname..tablename" queryout c:/DT.txt -c -Sservername -Usa -Ppassword’

导出到TXT文本,用逗号分开 
exec master..xp_cmdshell ’bcp "库名..表名" out "d:/tt.txt" -c -t ,-U sa -P password’


BULK INSERT 库名..表名 
FROM ’c:/test.txt’ 
WITH ( 
FIELDTERMINATOR = ’;’, 
ROWTERMINATOR = ’/n’ 
)


--/* dBase IV文件 
select * from 
OPENROWSET(’MICROSOFT.JET.OLEDB.4.0’ 
,’dBase IV;HDR=NO;IMEX=2;DATABASE=C:/’,’select * from [客户资料4.dbf]’) 
--*/

--/* dBase III文件 
select * from 
OPENROWSET(’MICROSOFT.JET.OLEDB.4.0’ 
,’dBase III;HDR=NO;IMEX=2;DATABASE=C:/’,’select * from [客户资料3.dbf]’) 
--*/

--/* FoxPro 数据库 
select * from openrowset(’MSDASQL’, 
’Driver=Microsoft Visual FoxPro Driver;SourceType=DBF;SourceDB=c:/’, 
’select * from [aa.DBF]’) 
--*/

/**************导入DBF文件****************/ 
select * from openrowset(’MSDASQL’, 
’Driver=Microsoft Visual FoxPro Driver; 
SourceDB=e:/VFP98/data; 
SourceType=DBF’, 
’select * from customer where country != "USA" order by country’) 
go 
/***************** 导出到DBF ***************/ 
如果要导出数据到已经生成结构(即现存的)FOXPRO表中,可以直接用下面的SQL语句

insert into openrowset(’MSDASQL’, 
’Driver=Microsoft Visual FoxPro Driver;SourceType=DBF;SourceDB=c:/’, 
’select * from [aa.DBF]’) 
select * from 表

说明: 
SourceDB=c:/ 指定foxpro表所在的文件夹 
aa.DBF 指定foxpro表的文件名.

 


/*************导出到Access********************/ 
insert into openrowset(’Microsoft.Jet.OLEDB.4.0’, 
’x:/A.mdb’;’admin’;’’,A表) select * from 数据库名..B表

/*************导入Access********************/ 
insert into B表 selet * from openrowset(’Microsoft.Jet.OLEDB.4.0’, 
’x:/A.mdb’;’admin’;’’,A表)

********************* 导入 xml 文件

DECLARE @idoc int 
DECLARE @doc varchar(1000) 
--sample XML document 
SET @doc =’ 
<root> 
<Customer cid= "C1" name="Janine" city="Issaquah"> 
<Order oid="O1" date="1/20/1996" amount="3.5" /> 
<Order oid="O2" date="4/30/1997" amount="13.4">Customer was very satisfied 
</Order> 
</Customer> 
<Customer cid="C2" name="Ursula" city="Oelde" > 
<Order oid="O3" date="7/14/1999" amount="100" note="Wrap it blue 
white red"> 
<Urgency>Important</Urgency> 
Happy Customer. 
</Order> 
<Order oid="O4" date="1/20/1996" amount="10000"/> 
</Customer> 
</root> 
’ 
-- Create an internal representation of the XML document. 
EXEC sp_xml_preparedocument @idoc OUTPUT, @doc

-- Execute a SELECT statement using OPENXML rowset provider. 
SELECT * 
FROM OPENXML (@idoc, ’/root/Customer/Order’, 1) 
WITH (oid char(5), 
amount float, 
comment ntext ’text()’) 
EXEC sp_xml_removedocument @idoc


/********************导整个数据库*********************************************/

用bcp实现的存储过程


/* 
实现数据导入/导出的存储过程 
根据不同的参数,可以实现导入/导出整个数据库/单个表 
调用示例: 
--导出调用示例 
----导出单个表 
exec file2table ’zj’,’’,’’,’xzkh_sa..地区资料’,’c:/zj.txt’,1 
----导出整个数据库 
exec file2table ’zj’,’’,’’,’xzkh_sa’,’C:/docman’,1

--导入调用示例 
----导入单个表 
exec file2table ’zj’,’’,’’,’xzkh_sa..地区资料’,’c:/zj.txt’,0 
----导入整个数据库 
exec file2table ’zj’,’’,’’,’xzkh_sa’,’C:/docman’,0

*/ 
if exists(select 1 from sysobjects where name=’File2Table’ and objectproperty(id,’IsProcedure’)=1) 
drop procedure File2Table 
go 
create procedure File2Table 
@servername varchar(200) --服务器名 
,@username varchar(200) --用户名,如果用NT验证方式,则为空’’ 
,@password varchar(200) --密码 
,@tbname varchar(500) --数据库.dbo.表名,如果不指定:.dbo.表名,则导出数据库的所有用户表 
,@filename varchar(1000) --导入/导出路径/文件名,如果@tbname参数指明是导出整个数据库,则这个参数是文件存放路径,文件名自动用表名.txt 
,@isout bit --1为导出,0为导入 
as 
declare @sql varchar(8000)

if @tbname like ’%.%.%’ --如果指定了表名,则直接导出单个表 
begin 
set @sql=’bcp 
+case when @isout=1 then ’ out ’ else ’ in ’ end 
+’ "" /w’ 
+’ /S 
+case when isnull(@username,’’)=’’ then ’’ else ’ /U end 
+’ /P ’+isnull(@password,’’) 
exec master..xp_cmdshell @sql 
end 
else 
begin --导出整个数据库,定义游标,取出所有的用户表 
declare @m_tbname varchar(250) 
if right(@filename,1)<>’/’ set @filename=@filename+’/’

set @m_tbname=’declare #tb cursor for select name from where xtype=’’U’’’ 
exec(@m_tbname) 
open #tb 
fetch next from #tb into @m_tbname 
while @@fetch_status=0 
begin 
set @sql=’bcp 
+case when @isout=1 then ’ out ’ else ’ in ’ end 
+’ " " /w’ 
+’ /S 
+case when isnull(@username,’’)=’’ then ’’ else ’ /U end 
+’ /P ’+isnull(@password,’’) 
exec master..xp_cmdshell @sql 
fetch next from #tb into @m_tbname 
end 
close #tb 
deallocate #tb 
end 
go


/**********************Excel导到Txt****************************************/ 
想用 
select * into opendatasource(...) from opendatasource(...) 
实现将一个Excel文件内容导入到一个文本文件

假设Excel中有两列,第一列为姓名,第二列为很行帐号(16位) 
且银行帐号导出到文本文件后分两部分,前8位和后8位分开。


如果要用你上面的语句插入的话,文本文件必须存在,而且有一行:姓名,银行账号1,银行账号2 
然后就可以用下面的语句进行插入 
注意文件名和目录根据你的实际情况进行修改.

insert into 
opendatasource(’MICROSOFT.JET.OLEDB.4.0’ 
,’Text;HDR=Yes;DATABASE=C:/’ 
)...[aa#txt] 
--,aa#txt) 
--*/ 
select 姓名,银行账号1=left(银行账号,8),银行账号2=right(银行账号,8) 
from 
opendatasource(’MICROSOFT.JET.OLEDB.4.0’ 
,’Excel 5.0;HDR=YES;IMEX=2;DATABASE=c:/a.xls’ 
--,Sheet1$) 
)...[Sheet1$]

如果你想直接插入并生成文本文件,就要用bcp

declare @sql varchar(8000),@tbname varchar(50)

--首先将excel表内容导入到一个全局临时表 
select @tbname=’[##temp’+cast(newid() as varchar(40))+’]’ 
,@sql=’select 姓名,银行账号1=left(银行账号,8),银行账号2=right(银行账号,8) 
into from 
opendatasource(’’MICROSOFT.JET.OLEDB.4.0’’ 
,’’Excel 5.0;HDR=YES;IMEX=2;DATABASE=c:/a.xls’’ 
)...[Sheet1$]’ 
exec(@sql)

--然后用bcp从全局临时表导出到文本文件 
set @sql=’bcp "" out "c:/aa.txt" /S"(local)" /P"" /c’ 
exec master..xp_cmdshell @sql

--删除临时表 
exec(’drop table )


用bcp将文件导入导出到数据库的存储过程:


/*--bcp-二进制文件的导入导出

支持image,text,ntext字段的导入/导出 
image适合于二进制文件;text,ntext适合于文本数据文件

注意:导入时,将覆盖满足条件的所有行 
导出时,将把所有满足条件的行也出到指定文件中

此存储过程仅用bcp实现 
邹建 2003.08-----------------*/

/*--调用示例 
--数据导出 
exec p_binaryIO ’zj’,’’,’’,’acc_演示数据..tb’,’img’,’c:/zj1.dat’

--数据导出 
exec p_binaryIO ’zj’,’’,’’,’acc_演示数据..tb’,’img’,’c:/zj1.dat’,’’,0 
--*/ 
if exists (select * from dbo.sysobjects where id = object_id(N’[dbo].[p_binaryIO]’) and OBJECTPROPERTY(id, N’IsProcedure’) = 1) 
drop procedure [dbo].[p_binaryIO] 
GO

Create proc p_binaryIO 
@servename varchar (30),--服务器名称 
@username varchar (30), --用户名 
@password varchar (30), --密码 
@tbname varchar (500), --数据库..表名 
@fdname varchar (30), --字段名 
@fname varchar (1000), --目录+文件名,处理过程中要使用/覆盖:@filename+.bak 
@tj varchar (1000)=’’, --处理条件.对于数据导入,如果条件中包含@fdname,请指定表名前缀 
@isout bit=1 --1导出((默认),0导入 
AS 
declare @fname_in varchar(1000) --bcp处理应答文件名 
,@fsize varchar(20) --要处理的文件的大小 
,@m_tbname varchar(50) --临时表名 
,@sql varchar(8000)

--则取得导入文件的大小 
if @isout=1 
set @fsize=’0’ 
else 
begin 
create table #tb(可选名 varchar(20),大小 int 
,创建日期 varchar(10),创建时间 varchar(20) 
,上次写操作日期 varchar(10),上次写操作时间 varchar(20) 
,上次访问日期 varchar(10),上次访问时间 varchar(20),特性 int) 
insert into #tb 
exec master..xp_getfiledetails @fname 
select @fsize=大小 from #tb 
drop table #tb 
if @fsize is null 
begin 
print ’文件未找到’ 
return 
end

end

--生成数据处理应答文件 
set @m_tbname=’[##temp’+cast(newid() as varchar(40))+’]’ 
set @sql=’select * into from( 
select null as 类型 
union all select 0 as 前缀 
union all select as 长度 
union all select null as 结束 
union all select null as 格式 
) a’ 
exec(@sql) 
select @fname_in=@fname+’_temp’ 
,@sql=’bcp "" out " 
+’" /S" 
+case when isnull(@username,’’)=’’ then ’’ 
else ’" /U" end 
+’" /P"’+isnull(@password,’’)+’" /c’ 
exec master..xp_cmdshell @sql 
--删除临时表 
set @sql=’drop table 
exec(@sql)

if @isout=1 
begin 
set @sql=’bcp "select top 1 from ’ 
isnull(@tj,’’) when ’’ then ’’ 
else ’ where end 
+’" queryout " 
+’" /S" 
+case when isnull(@username,’’)=’’ then ’’ 
else ’" /U" end 
+’" /P"’+isnull(@password,’’) 
+’" /i" 
exec master..xp_cmdshell @sql 
end 
else 
begin 
--为数据导入准备临时表 
set @sql=’select top 0 into ’ 
from ’ 
exec(@sql)

--将数据导入到临时表 
set @sql=’bcp "" in " 
+’" /S" 
+case when isnull(@username,’’)=’’ then ’’ 
else ’" /U" end 
+’" /P"’+isnull(@password,’’) 
+’" /i" 
exec master..xp_cmdshell @sql

--将数据导入到正式表中 
set @sql=’update 
+’ set 
+’ from a,’ 
b’ 
+case isnull(@tj,’’) when ’’ then ’’ 
else ’ where end 
exec(@sql)

--删除数据处理临时表 
set @sql=’drop table 
end

--删除数据处理应答文件 
set @sql=’del 
exec master..xp_cmdshell @sql

go


/** 导入文本文件 
EXEC master..xp_cmdshell ’bcp "dbname..tablename" in c:/DT.txt -c -Sservername -Usa -Ppassword’

改为如下,不需引号 
EXEC master..xp_cmdshell ’bcp dbname..tablename in c:/DT.txt -c -Sservername -Usa -Ppassword’

/** 导出文本文件 
EXEC master..xp_cmdshell ’bcp "dbname..tablename" out c:/DT.txt -c -Sservername -Usa -Ppassword’ 
此句需加引号 
 
By [zbkid] in [代码库] at 21:15:02 | Comments[0] | 37 views 
 什么是存储过程呢?

            定义:

            将常用的或很复杂的工作,预先用SQL语句写好并用一个指定的名称存储起来, 
            那么以后要叫数据库提供与已定义好的存储过程的功能相同的服务时,只需调用execute,即可自动完成命

令。

            讲到这里,可能有人要问:这么说存储过程就是一堆SQL语句而已啊?

            Microsoft公司为什么还要添加这个技术呢?

            那么存储过程与一般的SQL语句有什么区别呢?

            存储过程的优点:

            1.存储过程只在创造时进行编译,以后每次执行存储过程都不需再重新编译,而一般SQL语句每执行一次

就编译一次,所以使用存储过程可提高数据库执行速度。

            2.当对数据库进行复杂操作时(如对多个表进行Update,Insert,Query,Delete时),可将此复杂操作用存

储过程封装起来与数据库提供的事务处理结合一起使用。

            3.存储过程可以重复使用,可减少数据库开发人员的工作量

            4.安全性高,可设定只有某此用户才具有对指定存储过程的使用权

            存储过程的种类:

            1.系统存储过程:以sp_开头,用来进行系统的各项设定.取得信息.相关管理工作,

            如 sp_help就是取得指定对象的相关信息

            2.扩展存储过程 以XP_开头,用来调用操作系统提供的功能

            exec master..xp_cmdshell 'ping 10.8.16.1'

            3.用户自定义的存储过程,这是我们所指的存储过程

            常用格式

            Create procedure procedue_name

            [@parameter data_type][output]

            [with]{recompile|encryption}

            as

            sql_statement

            解释:

            output:表示此参数是可传回的

            with {recompile|encryption}

            recompile:表示每次执行此存储过程时都重新编译一次

            encryption:所创建的存储过程的内容会被加密

            如:

            表book的内容如下

            编号 书名 价格

            001 C语言入门 $30

            002 PowerBuilder报表开发 $52

            实例1:查询表Book的内容的存储过程

            create proc query_book

            as

            select * from book

            go

            exec query_book

            实例2:加入一笔记录到表book,并查询此表中所有书籍的总金额

            Create proc insert_book

            @param1 char(10),@param2 varchar(20),@param3 money,@param4 money 
            output

            with encryption ---------加密

            as

            insert book(编号,书名,价格) Values(@param1,@param2,@param3)
            select @param4=sum(价格) from book
            go

            执行例子: 
            declare @total_price money 
            exec insert_book '003','Delphi 控件开发指南',$100,@total_price
            print '总金额为'+convert(varchar,@total_price)
            go
            存储过程的3种传回值:
            1.以Return传回整数
            2.以output格式传回参数
            3.Recordset
            传回值的区别:
            output和return都可在批次程式中用变量接收,而recordset则传回到执行批次的客户端中

            实例3:设有两个表为Product,Order,其表内容如下:
            Product
            产品编号 产品名称 客户订数 
            001 钢笔 30 
            002 毛笔 50 
            003 铅笔 100 
            order 
            产品编号 客户名 客户订金
            001 南山区 $30
            002 罗湖区 $50
            003 宝安区 $4
            请实现按编号为连接条件,将两个表连接成一个临时表,该表只含编号.产品名.客户名.订金.总金额,
            总金额=订金*订数,临时表放在存储过程中

            代码如下:
            Create proc temp_sale
            as
            select a.产品编号,a.产品名称,b.客户名,b.客户订金,a.客户订数* b.客户订金 as总金额
            into #temptable from Product a inner join order b on a.产品编号=b.产品编号
            if @@error=0 
            print 'Good'
            else
            print 'Fail'
            go
语法

            CREATE PROC [ EDURE ] procedure_name [ ; number ]
                [ { @parameter data_type }
                    [ VARYING ] [ = default ] [ OUTPUT ]
                ] [ ,...n ] 
            [ WITH
                { RECOMPILE | ENCRYPTION | RECOMPILE , ENCRYPTION } ] 
            [ FOR REPLICATION ] 
            AS sql_statement [ ...n ]

            参数
            procedure_name
                新存储过程的名称。过程名必须符合标识符规则,且对于数据库及其所有者必须唯一。有关更多信息

,请参见使用标识符。
                要创建局部临时过程,可以在 procedure_name 前面加一个编号符 
            (#procedure_name),要创建全局临时过程,可以在 procedure_name 前面加两个编号符 
            (##procedure_name)。完整的名称(包括 # 或 ##)不能超过 128 个字符。指定过程所有者的名称是可

选的。

            ;number
                是可选的整数,用来对同名的过程分组,以便用一条 DROP PROCEDURE 语句即可将同组的过程一起除

去。例如,名为 
            orders 的应用程序使用的过程可以命名为 orderproc;1、orderproc;2 等。DROP PROCEDURE 
            orderproc 语句将除去整个组。如果名称中包含定界标识符,则数字不应包含在标识符中,只应在

procedure_name 
            前后使用适当的定界符。
            @parameter
            过程中的参数。在 CREATE PROCEDURE 
            语句中可以声明一个或多个参数。用户必须在执行过程时提供每个所声明参数的值(除非定义了该参数的

默认值)。存储过程最多可以有 2.100 
            个参数。
            使用 @ 
            符号作为第一个字符来指定参数名称。参数名称必须符合标识符的规则。每个过程的参数仅用于该过程本

身;相同的参数名称可以用在其它过程中。默认情况下,参数只能代替常量,而不能用于代替表名、列名或其它数据库

对象的名称。有关更多信息,请参见 
            EXECUTE。 
            data_type
            参数的数据类型。所有数据类型(包括 text、ntext 和 image)均可以用作存储过程的参数。不过,

cursor 数据类型只能用于 
            OUTPUT 参数。如果指定的数据类型为 cursor,也必须同时指定 VARYING 和 OUTPUT 关键字。有关 SQL 
            Server 提供的数据类型及其语法的更多信息,请参见数据类型。

            说明  对于可以是 cursor 数据类型的输出参数,没有最大数目的限制。

            VARYING
            指定作为输出参数支持的结果集(由存储过程动态构造,内容可以变化)。仅适用于游标参数。
            default
            参数的默认值。如果定义了默认值,不必指定该参数的值即可执行过程。默认值必须是常量或 NULL。如

果过程将对该参数使用 LIKE 
            关键字,那么默认值中可以包含通配符(%、_、[] 和 [^])。
            OUTPUT
            表明参数是返回参数。该选项的值可以返回给 EXEC[UTE]。使用 OUTPUT 参数可将信息返回给调用过程。

Text、ntext 和 
            image 参数可用作 OUTPUT 参数。使用 OUTPUT 关键字的输出参数可以是游标占位符。
            n
            表示最多可以指定 2.100 个参数的占位符。
            {RECOMPILE | ENCRYPTION | RECOMPILE, ENCRYPTION}
            RECOMPILE 表明 SQL Server 
            不会缓存该过程的计划,该过程将在运行时重新编译。在使用非典型值或临时值而不希望覆盖缓存在内存

中的执行计划时,请使用 RECOMPILE 
            选项。
            ENCRYPTION 表示 SQL Server 加密 syscomments 表中包含 CREATE PROCEDURE 
            语句文本的条目。使用 ENCRYPTION 可防止将过程作为 SQL Server 复制的一部分发布。

            说明  在升级过程中,SQL Server 利用存储在 syscomments 中的加密注释来重新创建加密过程。

            FOR REPLICATION
            指定不能在订阅服务器上执行为复制创建的存储过程。.使用 FOR REPLICATION 
            选项创建的存储过程可用作存储过程筛选,且只能在复制过程中执行。本选项不能和 WITH RECOMPILE 选

项一起使用。
            AS
            指定过程要执行的操作。
            sql_statement
            过程中要包含的任意数目和类型的 Transact-SQL 语句。但有一些限制。
            n
            是表示此过程可以包含多条 Transact-SQL 语句的占位符。
            注释
            存储过程的最大大小为 128 MB。
            用户定义的存储过程只能在当前数据库中创建(临时过程除外,临时过程总是在 tempdb 中创建)。在单

个批处理中,CREATE 
            PROCEDURE 语句不能与其它 Transact-SQL 语句组合使用。 
            默认情况下,参数可为空。如果传递 NULL 参数值并且该参数在 CREATE 或 ALTER TABLE 
            语句中使用,而该语句中引用的列又不允许使用 NULL,则 SQL Server 会产生一条错误信息。为了防止

向不允许使用 NULL 
            的列传递 NULL 参数值,应向过程中添加编程逻辑或为该列使用默认值(使用 CREATE 或 ALTER TABLE

的 DEFAULT 
            关键字)。
            建议在存储过程的任何 CREATE TABLE 或 ALTER TABLE 语句中都为每列显式指定 NULL 或 NOT 
            NULL,例如在创建临时表时。ANSI_DFLT_ON 和 ANSI_DFLT_OFF 选项控制 SQL Server 为列指派 
            NULL 或 NOT NULL 特性的方式(如果在 CREATE TABLE 或 ALTER TABLE 
            语句中没有指定的话)。如果某个连接执行的存储过程对这些选项的设置与创建该过程的连接的设置不同

,则为第二个连接创建的表列可能会有不同的为空性,并且表现出不同的行为方式。如果为每个列显式声明了 
            NULL 或 NOT NULL,那么将对所有执行该存储过程的连接使用相同的为空性创建临时表。
            在创建或更改存储过程时,SQL Server 将保存 SET QUOTED_IDENTIFIER 和 SET ANSI_NULLS 
            的设置。执行存储过程时,将使用这些原始设置。因此,所有客户端会话的 SET QUOTED_IDENTIFIER 和

SET 
            ANSI_NULLS 设置在执行存储过程时都将被忽略。在存储过程中出现的 SET QUOTED_IDENTIFIER 和 SET 
            ANSI_NULLS 语句不影响存储过程的功能。
            其它 SET 选项(例如 SET ARITHABORT、SET ANSI_WARNINGS 或 SET 
            ANSI_PADDINGS)在创建或更改存储过程时不保存。如果存储过程的逻辑取决于特定的设置,应在过程开

头添加一条 SET 
            语句,以确保设置正确。从存储过程中执行 SET 
            语句时,该设置只在存储过程完成之前有效。之后,设置将恢复为调用存储过程时的值。这使个别的客户

端可以设置所需的选项,而不会影响存储过程的逻辑。

            说明  SQL Server 是将空字符串解释为单个空格还是解释为真正的空字符串,由兼容级别设置控制。如

果兼容级别小于或等于 
            65,SQL Server 就将空字符串解释为单个空格。如果兼容级别等于 70,则 SQL Server 
            将空字符串解释为空字符串。有关更多信息,请参见 sp_dbcmptlevel。

            获得有关存储过程的信息
            若要显示用来创建过程的文本,请在过程所在的数据库中执行 sp_helptext,并使用过程名作为参数。

            说明  使用 ENCRYPTION 选项创建的存储过程不能使用 sp_helptext 查看。

            若要显示有关过程引用的对象的报表,请使用 sp_depends。 
            若要为过程重命名,请使用 sp_rename。 
            引用对象
            SQL Server 
            允许创建的存储过程引用尚不存在的对象。在创建时,只进行语法检查。执行时,如果高速缓存中尚无有

效的计划,则编译存储过程以生成执行计划。只有在编译过程中才解析存储过程中引用的所有对象。因此,如果语法正

确的存储过程引用了不存在的对象,则仍可以成功创建,但在运行时将失败,因为所引用的对象不存在。有关更多信息

,请参见延迟名称解析和编译。

            延迟名称解析和兼容级别
            SQL Server 允许 Transact-SQL 存储过程在创建时引用不存在的表。这种能力称为延迟名称解析。不过

,如果 
            Transact-SQL 存储过程引用了该存储过程中定义的表,而兼容级别设置(通过执行 sp_dbcmptlevel 来

设置)为 
            65,则在创建时会发出警告信息。而如果在运行时所引用的表不存在,将返回错误信息。有关更多信息,

请参见 sp_dbcmptlevel 
            和延迟名称解析和编译。 
            执行存储过程
            成功执行 CREATE PROCEDURE 语句后,过程名称将存储在 sysobjects 系统表中,而 CREATE 
            PROCEDURE 语句的文本将存储在 syscomments 中。第一次执行时,将编译该过程以确定检索数据的最佳

访问计划。
            使用 cursor 数据类型的参数
            存储过程只能将 cursor 数据类型用于 OUTPUT 参数。如果为某个参数指定了 cursor 数据类型,也必须

指定 VARYING 
            和 OUTPUT 参数。如果为某个参数指定了 VARYING 关键字,则数据类型必须是 cursor,并且必须指定

OUTPUT 
关键字。

            说明  cursor 数据类型不能通过数据库 API(例如 OLE DB、ODBC、ADO 和 
            DB-Library)绑定到应用程序变量上。因为必须先绑定 OUTPUT 参数,应用程序才可以执行存储过程,所

以带有 cursor 
            OUTPUT 参数的存储过程不能通过数据库 API 调用。只有将 cursor OUTPUT 变量赋值给 Transact-SQL

局部 
            cursor 变量时,才可以通过 Transact-SQL 批处理、存储过程或触发器调用这些过程。

            Cursor 输出参数
            在执行过程时,以下规则适用于 cursor 输出参数: 
            对于只进游标,游标的结果集中返回的行只是那些存储过程执行结束时处于或超出游标位置的行,例如: 
            在过程中的名为 RS 的 100 行结果集上打开一个非滚动游标。

            过程提取结果集 RS 的头 5 行。

            过程返回到其调用者。

            返回到调用者的结果集 RS 由 RS 的第 6 到 100 行组成,调用者中的游标处于 RS 的第一行之前。 
            对于只进游标,如果存储过程完成后,游标位于第一行的前面,则整个结果集将返回给调用批处理、存储

过程或触发器。返回时,游标将位于第一行的前面。

            对于只进游标,如果存储过程完成后,游标的位置超出最后一行的结尾,则为调用批处理、存储过程或触

发器返回空结果集。 
            说明  空结果集与空值不同。
            对于可滚动游标,在存储过程执行结束时,结果集中的所有行均会返回给调用批处理、存储过程或触发器

。返回时,游标保留在过程中最后一次执行提取时的位置。

            对于任意类型的游标,如果游标关闭,则将空值传递回调用批处理、存储过程或触发器。如果将游标指派

给一个参数,但该游标从未打开过,也会出现这种情况。

            说明  
关闭状态只有在返回时才有影响。例如,可以在过程中关闭游标,稍后再打开游标,然后将该游标的结果集返回给调用

批处理、存储过程或触发器。

            临时存储过程
            SQL Server 
            支持两种临时过程:局部临时过程和全局临时过程。局部临时过程只能由创建该过程的连接使用。全局临

时过程则可由所有连接使用。局部临时过程在当前会话结束时自动除去。全局临时过程在使用该过程的最后一个会话结

束时除去。通常是在创建该过程的会话结束时。
            临时过程用 # 和 ## 
            命名,可以由任何用户创建。创建过程后,局部过程的所有者是唯一可以使用该过程的用户。执行局部临

时过程的权限不能授予其他用户。如果创建了全局临时过程,则所有用户均可以访问该过程,权限不能显式废除。只有

在 
            tempdb 数据库中具有显式 CREATE PROCEDURE 
            权限的用户,才可以在该数据库中显式创建临时过程(不使用编号符命名)。可以授予或废除这些过程中

的权限。

            说明  频繁使用临时存储过程会在 tempdb 中的系统表上产生争用,从而对性能产生负面影响。建议使用

sp_executesql 
            代替。sp_executesql 不在系统表中存储数据,因此可以避免这一问题。

            自动执行存储过程
            SQL Server 启动时可以自动执行一个或多个存储过程。这些存储过程必须由系统管理员创建,并在

sysadmin 
            固定服务器角色下作为后台过程执行。这些过程不能有任何输入参数。 
            对启动过程的数目没有限制,但是要注意,每个启动过程在执行时都会占用一个连接。如果必须在启动时

执行多个过程,但不需要并行执行,则可以指定一个过程作为启动过程,让该过程调用其它过程。这样就只占用一个连

接。
            在启动时恢复了最后一个数据库后,即开始执行存储过程。若要跳过这些存储过程的执行,请将启动参数

指定为跟踪标记 4022。如果以最低配置启动 
            SQL Server(使用 -f 标记),则启动存储过程也不会执行。有关更多信息,请参见跟踪标记。 
            若要创建启动存储过程,必须作为 sysadmin 固定服务器角色的成员登录,并在 master 数据库中创建存

储过程。
            使用 sp_procoption 可以: 
            将现有存储过程指定为启动过程。

            停止在 SQL Server 启动时执行过程。

            查看 SQL Server 启动时执行的所有过程的列表。 
            存储过程嵌套
            存储过程可以嵌套,即一个存储过程可以调用另一个存储过程。在被调用过程开始执行时,嵌套级将增加

,在被调用过程执行结束后,嵌套级将减少。如果超出最大的嵌套级,会使整个调用过程链失败。可用 
            @@NESTLEVEL 函数返回当前的嵌套级。
            若要估计编译后的存储过程大小,请使用下列性能监视计数器。 
            性能监视器对象名 性能监视计数器名称 
            SQLServer:缓冲区管理器 高速缓存大小(页面数) 
            SQLServer:高速缓存管理器 高速缓存命中率 
              高速缓存页 
              高速缓存对象计数*

            * 各种分类的高速缓存对象均可以使用这些计数器,包括特殊 sql、准备 sql、过程、触发器等。
            有关更多信息,请参见 SQL Server:Buffer Manager 对象和 SQL Server:Cache Manager 
            对象。 
            sql_statement 限制
            除了 SET SHOWPLAN_TEXT 和 SET SHOWPLAN_ALL 之外(这两个语句必须是批处理中仅有的语句),任何

SET 
            语句均可以在存储过程内部指定。所选择的 SET 选项在存储过程执行过程中有效,之后恢复为原来的设

置。 
            如果其他用户要使用某个存储过程,那么在该存储过程内部,一些语句使用的对象名必须使用对象所有者

的名称限定。这些语句包括: 
            ALTER TABLE

            CREATE INDEX

            CREATE TABLE

            所有 DBCC 语句

            DROP TABLE

            DROP INDEX

            TRUNCATE TABLE

            UPDATE STATISTICS 
            权限
            CREATE PROCEDURE 的权限默认授予 sysadmin 固定服务器角色成员和 db_owner 和 db_ddladmin 
            固定数据库角色成员。sysadmin 固定服务器角色成员和 db_owner 固定数据库角色成员可以将 CREATE

PROCEDURE 
            权限转让给其他用户。执行存储过程的权限授予过程的所有者,该所有者可以为其它数据库用户设置执行

权限。