当前位置:首页 » 服务存储 » 存储过程中的语句在哪里
扩展阅读
webinf下怎么引入js 2023-08-31 21:54:13
堡垒机怎么打开web 2023-08-31 21:54:11

存储过程中的语句在哪里

发布时间: 2022-08-10 02:20:01

1. 如何查看存储过程运行到哪个语句了

存储过程(procere 过程)

sql Server2005 的存储过程包含一些 T-SQL 语句并以特定的名称存储在数据中(存储过程也是一种数据库对象)可以在存储过程中声明变量,有条件的执行及其他各项强大的程序设计功能

SQL Server2005 的存储过程与其它育种设计语言的过程类似,同样按以下方式运行:
(1)它能够包含执行各种数据库操作的语句,并且可以调用其他的存储过程;
(2)能够接受输入参数,并以输出参数的形式将多个数据值返回给调用程序(Calling Procere)或批处理(Batch);
(3)向调用程序或批处理返回一个状态值,以表明成功或失败(以及失败的原因);
(4)存储过程(Stored Proceres) 是一组为完成特定功能的SQL 语句集,经编译后,存储在数据库中,用户通过指定存储过程的名字给出参
数(如果该存储过程带有参数)来执行它;

存储过程的类型:
一、(系统存储过程):存储过程在运行时生成执行方式,其后在运行时执行速度很
SQL Server2005 不仅提供用户自定义存储过程的功能,而且也提供许多可作为工具使用的系统存储过程;
系统存储过程(Systerm StroedProceres) 主要存储在master数据库中,并以 sp_ 为前辍,并且系统存储过程主要是从系统表中获取信息,从而为管理员SQL Server2005提供支持。通过系统存储过程SQL Server2005中的许多管理性或信息性的活动(如了解数据对象,数据库信息等)都可以被有效地完成,尽管这些系统存储过程被存储在master数据库中,但是仍然可以在其他 数据库中对其进行调用,在调用时,不必在存储过程前面加上数据库名,而且当创建一个数据库时,一些存储过程会在新的数据库中被自动创建;
系统存储过程所能完成操作很多,如提供帮助的存储过程
sp_helpsql 显示关于SQL语句,存储过程和其他主题的信息
sp_help 提供关于存储过程或其他数据库对象的报告
sp_helptext 显示存储过程和其他对象文本
sp_depends 列举引用或依赖指定对象的所有存储过程
sp_talbes 取得数据库中关于表和视图的相关信息,
sp_renameedb 更改数据库的名称

SQL Server2005系统存储过程可以使用户很容易地从系统表中提取信息,管理数据库,并执行涉及更新系统表的其他任务
系统存储过程中在master数据库中创建,由系统管理员管理,所有系统存储过程的名字均以sp_开始
如果过程以sp_前缀命名的过程在当前数据库中找不到,SQL Server2005就在master数据库中寻找,以sp_前缀命名的过程中引用的表如果不能在当前数据库中解析出来,将在master数据库查找

当前系统存储过程的参数是保留字或对象名,且对象名由数据库或拥有者名字限定时,整个名字必须包含在单引号中,一个用户可以在所有数据库中执行一个系统存储过程的许可权,否则在任何数据库中都不能执行系统存储过程

二、(本地存储过程)
本地存储过程(Local Stored Proceres)也就是用户自行创建并存储在用户数据库中的存储过程,一般所说的存储过程就是指的是本地的
用户创建的存储过程是由用户创建并能完成某一特定功能(如:查询用户所需要的数据信息)的存储过程

三、(临时存储过程)
临时存储过程(Temporary StoredProceres)可分为以下两种
1)本地临时存储过程
不论哪一个数据库是当前数据库,如果在创建存储过程时,以井字号 (#) 作为其名称的,第一个字符,则该存储过程将成为一个存放在tempdb数据库中的本地临时存放存储过程(如:CREATE PROCEDURE #book_proc) 本地临时存储过程只有创建它的连接的用户才能够执行它,而且一但这位用户断开与 sql-server的连接(也就是注销sql-server2005)本地临时存储过程就会自动删除,当然,这位用户也可以连接期间用 DROP PROCEDURE 命令删除他所创建的本地临时存储过程;
由于本地存储过程的适用范围仅限于创建它的连接,因此,不需担心其名称会和其他连接所采用的名称相同

2)全临时存储过程
不论哪一个数据库当前数据库,只要所创建的存储过程名称是以两个井字号(##)开始,则该存储过程将成为一个存储在tempdb 数据库中的全局临时存储过程(例如:create procere ##book_proc) 全局临时存储过程一旦创建,以后连接到 SQL Server2005 的任意用户都能执行它,而且不需要特定的权限
当创建全局临时存储过程的用户断开与SQL Server2005的连接时,SQL Server2005将检查是否有其他用户在执行该全局临时存储过程,如果没有,便立刻将全局临时存储过程删除,如果有SQL Server2005会让这些正在执行中的操作继续进行,但是不允许任何用户再执行全局临时存储过程,等到有未完成的操作执行完毕后,全局临时存储过程就会自动删除;
由于全局临时存储过程能够被所有的连接用户使用,因些必须注意其名称不能和其他连接所采用的名称相同
不论创建的是本地临时存储过程还是全局临时存储过程,只要SQL Server2005一停止运行,它们将不复存在;

四(远程存储过程)
在SQL Server2005 中,远程存储过程(Remote Stored Proceres)是位于远程服务器上的存储过程,通常可以使用分布式查询和 excute 命令执行一个远程存储过程;

五(扩展存储过程)
扩展存储过程(Extended Stored Proceres)是用户可以使用外部程序语言编写的存储过程,通过扩展存储过程可以弥补SQL Server2005的不足,它在使用和执行上与一般的存储过程完全相同;可以将参数传递给扩展存储过程,扩展存储过程也能够返回结果和状态值;
为了区别扩展存储过程的名称通常以xp_开头,扩展存储过程是以动态链接库(DLLS)的形式存在,能让SQL Server2005动态地装载和执行,扩展存储过程一定要存储在系统数据库 master 中

存储过程的优点
(1) 通过本地存储、代码预编译和缓存技术实现高性能的数据操作
(2) 通过用编程结构和过程实现编程框架;如果业务规则发生变化,可以通过修改存储过程来适应新的业务规则,而不必修改客户端的应用程 序,这样所有调用该存储过程的应用程序就会遵循新的业务规则;
(3) 通过隔离和加密的方法提高数据库的安全性。数据库可以通过得到权限来执行存储过程,而不必给予用户直接访问数据库对象的权限,这 些对象交收存储过程来执行操作,另外,存储过程可以加密,这样用户就无法阅读存储过程中的T-sql语句。这样做将数据库的结构和数 据库用户隔离开来,时一步保证数据的完整性和可靠性;

存储过程与视图的比较
(1) 可以在单个存储过程执行一系列T-SQL 语句,而在视图中只能是 select 语句
(2) 视图不能接受参数,只能返回结果集;而存储过程可以接受参数,包括输入,输出参数,并能返回单个或多个结果集以及返回值,这样可 大大地提高应用的灵活性;
一般来说,人们将经常用到的多个表的连接查询定义为视图,而存储过程完成复杂的一第列的处理,在存储过程中也会经常用到视图;

创建存储过程
CREATE PROCEDURE procere_name
[WITH ENCRYPTION]
[WITH RECOMPILE]
AS
Sql_statement

其中 with encryption 对存储过程进行加密; with recompile 对存储过程重新编译
例如:使用T-SQL 语句在book数据库中创建一个名为p_book1的存储过程 该存储过程返回book1表中所有出版社为"中国长安"的记录
USE book
GO
CREATE PROCEDURE p_book1
AS
SELECT * FROM book1 WHERE 出版社='中国长安'

执行存储过程

存储过程创建成功后,用户可以执行存储过程来检查存储过程的返回结果;基本语法如下:
exec procere_name
例如:使用T-SQL语句执行上面创建的存储过程 运行命令如下:
USE book
GO
exec p_book1
在运行完毕后,在SQL-Server ManagementStudio 查询窗口中返回的结果
存储过程创建成功后可以在 SQL-Server ManagementStudio 窗口中下查看存储过程的属性
例如:在 SQL-Server ManagementStudio 窗口中查看存储过程 p_book1 的属性:
对象资源管理器-> 展开book选项-> 展开可编程性-> 右击 p_book1选择修改命令 就可以修改存储过程命令属性

带参数的存储过程

由于视图没有提供参数,对于行的筛选取只能绑定在视图中定义,灵活性不大,而存储过程提供了参数,大大提高了系统开发的灵活性
向存储过程设定输入、输出参数主要目的是通过参数向存储过程输入和输出信息来扩展存储过程的功能,能过设定能数,可以多次使用同一存储过程并按要求查找所需要的结果;

1、带输入参数的存储过程
输入参数是指由调用程序向存储过程传递的参数,它们在创建存储过程语句中被定义,在执行存储过程中给出相应的变量值,为了定义输入参数存储过程,需要在 create procere 语句中声明一个或多个变量作为参数;其语法格式如下:
CREATE PROCEDURE procerd_name
@parameter_name datatype=[default]
[with encryption]
[with recompile]
AS
Sql_statement

其中各项参数如下
(1) @parameter_name: 存储过程的参数名称,必须以符号@为前缀
(2) Datatype: 参数的数据类型
(3) Default: 参数的默认值,如果执行存储过程时未提供该参数的变量值,则使用default值

例子:使用T-SQL语句在book数据表中创建一个名为p_book1p的存储过程,该存储过程能根据给定的出版社回该出版社代码对应的book1表中的的记录:

分析:直接把上面的例子最后面的SQL语句 select * from book1 where 出版社='中国长安' 将里面的 “出版社='中国长安'”用变理代替为 select * from book1 where 出版社= @出版社 其中变量名 @出版社取了代值 '中国长安';由于使用了变量,所以需要定义该变量,我们把“出版社”的长度设为是20位字符串;所以在 AS 之前定义变更@出版社 varchar(20);

create procere p_book1p
@出版社 varchar(20)
AS
SELECT * FROM book1 WHERE 出版社=@出版社

执行含有输入参数的存储过程
1)使用参数名传递参数值
在执行存储过程的语句中通过语句 @paramter_name=value 给出参数的传递值,当存储过程含有多个参数时,参数值可以任意顺序设定,对于允许空值和具有默认值的输入参数可以不给出参数的传递值;其格式语法如下:
exec procere_name
[@paramenter_name=value]
[,....n]
例子:用参数名传递参数值的方法执行存储过程p_book1p,分别查出出版社为'中国长安'和"安徽人民"书的记录
exec p_book1p @出版社='中国长安'
go
exec p_book1p @出版社='安徽人民'
go

2) 按位置传递参数值
在执行存储过程的语句中,不通过参数传递值面直接给出参数的传递值,当存储过程含有多个输入参数时,传递值的顺序必须与存储过程中定义的输入参数顺序相一致,按位置传递参数时,也可以忽略空值和具有默认值的参数,但不能因此破坏输入参数的设定顺序;比如:在一个含有4个参数的存储过程中,用户可以忽略第3和第四个参数,但无法在忽略第3个的情况下而指定第4个参数的输入值;
语法格式如下:
exec procere_name
[value1,value2,....]

例子:用按位置传递参数值的方法执行存储过程 p_book1p 分别查找出版社为“中国人口”和“内蒙人民”书的记录
exec p_book1p '内蒙人民'
go
exec p_book1p '中国人口'
go

按位置传递参数值比按参数名传递参数值更简捷比较适合参数值较少的情况,而按照参数名传递的方法使程序的可读性增强,特别是参数数量较多时,建议用按参数名传递参数的方法,这样的程序可读性/可维护性都要好一些;

3) 带输出参数的存储过程
如果需要从存储过程中返回一个或多个值,可以通过在创建存储过程的语句中定义输出参数来实现,为了使用输出参数,需要在
create procere 语句中指定 output 关键字 输出语法如下: @parameter_name datatype=[defautl] OUTPUT
例如:创建存储过程 p_book1Num 要求能根据用户给定的出版社,统计该出版社的出书数量,并将数量以输入变量的形式返回给用户:
CREATE PROCEDURE p_bookNum
@出版社 var(20),@bookNum smallint output
AS
SET @BOOK1Num= --(这个里面是给book1Num 赋值)
(
select count(*) from book1
where 出版社=@出版社
)
ptrint @book1Num

执行存储过程p_book1Num
由于在存储过程 p_book1Num 中使用了参数@出版社和@book1Num 所以在测试时需要先定义相应的变量,对于输入参数@出版社需要赋值,而输出参数 @book1Num 无需赋值,它是从存储过程中获得返回值供用户进一步使用的

declare @出版社 varchar(20), @book1Num SMALLINT
set @出版社=“中国长安”
exec p_book1Num @出版社,@book1Num

说明:这里在是sql server2005 环境下进行测试的,而在进行系统开发时,往往变量的定义,赋值,使用都是在应用程序中设计的,存储过程 p_book1Num 的 print @book1Num语句也是为了在 SQL Server2005环境中测试而设计的

删除、修改、重命名存储过程

修改存储过程:是由alert 语句来完成的,语法如下:
ALTER procere procere_name
[with encryption]
[with recompile]
as
Sql_statement
例子:使用T-SQL语句修改存储过程 p_book1p 根据用户提供的出版社名称进行模糊查询并要求加密:

alter procere p_book1p
@出版社 varchar(20)
with encryption
as
select 出版社,ISBN号,定价,作者姓名
from book1,teacher
where book1.编号=teacher.编号 and 出版社 like '%@出版社%'

存储过程的删除:存储过程的删除是通过DROP语句来实现的
例如:使用T-SQL语句来删除存储过程p_book1
use book
go
drop procere p_book1

使用SQL-Server Management Studio窗口删除存储过程 p_book1p:
对象资源管理器-> 展开BOOK-> 展开可编程性-> 右键dbo.p_book1p->删除 就可以了

存储过程重命名:
对象资源管理器-> 展开BOOK-> 展开可编程性-> 右键dbo.p_book1p->重命名

存储过程的重编译处理
在存储过程中所用的查询只在编译时进行优化,对数据库进行索引或其他会影响数据库统计的更改后,可能降低已编译的存储过程的效率,通过对存储过程进行重新编译,可以重新优化查询;
在SQL-Server2005 中有三种方法重新编译的方法:
1) 在创建存储过程时使用 with recompile 子句
with recompile 子句可以指示 sql server2005 不将该存储过程的查询计划保存在缓存中,而是在每次运行时重新编译和优化,并创建新 的查询计划;下面是例子:
use book
go
create procere p_book1p
@出版社 varchar(20)
with recompile
as
select * from book1 where 出版社=@出版社
这种方法并不常用,因为在每次执行存储过程时都要重新编译,在整体上降低了存储过程的执行速度,除非存储过程本身是一个比较复杂,耗时的操作,编译的时间相对于执行存储过程时间少;

2) 在执行存储过程时设定重新编译选项
通过在执行存储过程时设定重新编译,可以让SQL-Server2005在执行存储过程时重新编译该存储过程,在这一次执行后,新的查询计划又被保存在缓存中;基语法格式是:
execute procere_name with recompile
以重新编译的方式执行存储过程p_book1p:
use book
go
execute p_book1p '中国长安'with recompile 此方法一般在存储过程创建后,数据发生了显着变化时使用

3) 通过系统存储过程设定重新编译选择;其语法如下
exec sp_recomplie OBJECT 其中OBJECT 当前数据库中的存储过程,表或视图的名称
例子:执行下面的语句将导致book1表的触发器和存储过程在下次运行时将被重新编译:
exec sp_recompile book

===========================================================================================================================
触发器的创建和管理

概述:在SQL-Server2005数据库系统中,存储过程和触发器都是SQL语句和流程控制语句的集合

===========================================================================================================================

2. 在SQL中存储过程的一般语法是什么

1、 创建语法

createproc|procerepro_name

[{@参数数据类型}[=默认值][output],

{@参数数据类型}[=默认值][output],

....

]

as

SQL_statements

2、 创建不带参数存储过程

--创建存储过程

if(exists(select*fromsys.objectswherename='proc_get_student'))

dropprocproc_get_student

go

createprocproc_get_student

as

select*fromstudent;

--调用、执行存储过程

execproc_get_student;

3、 修改存储过程

--修改存储过程

alterprocproc_get_student

as

select*fromstudent;

4、 带参存储过程

--带参存储过程

if(object_id('proc_find_stu','P')isnotnull)

dropprocproc_find_stu

go

createprocproc_find_stu(@startIdint,@endIdint)

as

select*fromstudentwhereidbetween@startIdand@endId

go

execproc_find_stu2,4;

5、 带通配符参数存储过程

--带通配符参数存储过程

if(object_id('proc_findStudentByName','P')isnotnull)

dropprocproc_findStudentByName

go

createprocproc_findStudentByName(@namevarchar(20)='%j%',@nextNamevarchar(20)='%')

as

select*fromstudentwherenamelike@nameandnamelike@nextName;

go

execproc_findStudentByName;execproc_findStudentByName'%o%','t%';

(2)存储过程中的语句在哪里扩展阅读:

SQL存储过程优点:

1、重复使用。存储过程可以重复使用,从而可以减少数据库开发人员的工作量。

2、减少网络流量。存储过程位于服务器上,调用的时候只需要传递存储过程的名称以及参数就可以了,因此降低了网络传输的数据量。

3、安全性。参数化的存储过程可以防止SQL注入式攻击,而且可以将Grant、Deny以及Revoke权限应用于存储过程。

3. oracle 存储过程中的语句

解答如下:
1、CREATE
GLOBAL
TEMPORARY
TABLE
T_TEMP
语句是创建一个临时表,oracle中创建临时表有两种,一种是事务级的,一种是会话级的,当创建临时表语句后面有ON
COMMIT
delete
ROWS时表示该临时表是事务级的,ON
COMMIT
PRESERVE
ROWS
时表示该临时表是会话级的。
2、execute
immediate
是动态执行sql语句。
上面语句的意思是动态执行一条创建事务级临时表的ddl语句。

4. sql 存储过程查询语句

在数据库中先创建存储过程!具体代码如下:
create proc sp_GetTesttableByname --sp_GetTesttableByname代表存储过程名称
as
begin
SELECT nickname,email FROM testtable WHERE name='张三' --存数过程的查询语句
end
go
exec sp_GetTesttableByname; --查询存储过程结果

按下F5执行以上代码之后 然后再在项目中写调用存储过程语句!希望我的回答对你有所帮助,谢谢采纳!

5. 怎么查看一个存储过程的SQL语句

查看一个存储过程的SQL语句步骤如下:

1、开启Microsoft SQL Server数据库管理工具,输入账号密码连接到数据库。

6. 请问怎么可以查找出SQL的存储过程中找出我想要的语句呢

表syscomments存放存储过程的语句
SELECT * FROM syscomments WHERE (text LIKE '%insert into%')

7. 找到sql语句在哪个存储过程

sql server 么? 用性能监视器监视,再搜索看看行不行,或者直接在数据库里面列出所有存储过程的语句对比下

8. 存储过程怎么查看执行sql语句

MSSQL为我们提供了两种动态执行SQL语句的命令,分别是EXEC和
sp_executesql;通常,sp_executesql则更具有优势,它提供了输入输出接口,而EXEC没有。还有一个最大的好处就是利用
sp_executesql,能够重用执行计划,这就大大提供了执行性能,还可以编写更安全的代码。EXEC在某些情况下会更灵活。除非您有令人信服的理
由使用EXEC,否侧尽量使用sp_executesql.

1.EXEC的使用

EXEC命令有两种用法,一种是执行一个存储过程,另一种是执行一个动态的批处理。以下所讲的都是第二种用法。

下面先使用EXEC演示一个例子,代码1

代码

DECLARE @TableName VARCHAR(50),@Sql NVARCHAR (MAX),@OrderID INT;
SET @TableName = 'Orders';
SET @OrderID = 10251;
SET @sql =
'SELECT * FROM '+QUOTENAME(@TableName) +'WHERE OrderID = '+
CAST(@OrderID AS VARCHAR(10))+' ORDER BY ORDERID DESC'
EXEC(@sql);

注:这里的EXEC括号中只允许包含一个字符串变量,但是可以串联多个变量,如果我们这样写EXEC:

EXEC('SELECT TOP('+ CAST(@TopCount AS VARCHAR(10)) +')* FROM '+
QUOTENAME(@TableName) +' ORDER BY ORDERID DESC');

SQL编译器就会报错,编译不通过,而如果我们这样:

EXEC(@sql+@sql2+@sql3);

编译器就会通过;

所以最佳的做法是把代码构造到一个变量中,然后再把该变量作为EXEC命令的输入参数,这样就不会受限制了。

EXEC的缺点是不提供接口,这里的接口是指,它不能执行一个包含一个带变量符的批处理,如下

代码

DECLARE @TableName VARCHAR(50),@Sql NVARCHAR(MAX),@OrderID INT;
SET @TableName = 'Orders';
SET @OrderID = 10251;
SET @sql = 'SELECT * FROM '+QUOTENAME(@TableName) +
'WHERE OrderID = @OrderID ORDER BY ORDERID DESC'
EXEC(@sql);

关键就在SET @sql这一句话中,如果我们运行这个批处理,编译器就会产生一下错误

Msg 137, Level 15, State 2, Line 1
必须声明标量变量 "@OrderID"。

使用EXEC时,如果您想访问变量,必须把变量内容串联到动态构建的代码字符串中,如:

SET @sql = 'SELECT * FROM '+QUOTENAME(@TableName) + 'WHERE OrderID = '+CAST(@OrderID AS VARCHAR(10))+' ORDER BY ORDERID DESC'

串联变量的内容也存在性能方面的弊端。SQL Server为每一个的查询字符串创建新的执行计划,即使查询模式相同也是这样。为演示这一点,先清空缓存中的执行计划

DBCC FREEPROCCACHE (这个不是本文所涉及的内容,您可以查看MS的MSDN)

将代码1运行3次,分别对@OrderID 赋予下面3个值,10251,10252,10253。然后使用下面的代码查询

SELECT cacheobjtype,objtype,usecounts,sql FROM sys.syscacheobjects WHERE sql NOT LIKE '%cach%' AND sql NOT LIKE '%sys.%'

点击F5运行,我们可以看到,每执行一次都要产生一次的编译,执行计划没有得到充分重用。

EXEC除了不支持动态批处理中的输入参数外,他也不支持输出参数。默认情况下,EXEC把查询的输出返回给调用者。例如下面代码返回Orders表中所有的记录数

DECLARE @sql NVARCHAR(MAX)
SET @sql = 'SELECT COUNT(ORDERID) FROM Orders';
EXEC(@sql);

然而,如果你要把输出返回给调用批处理中的变量,事情就没有那么简单了。为此,你必须使用INSERT EXEC语法把输出插入到一个目标表中,然后从这表中获取值后赋给该变量,就像这样:

代码

DECLARE @sql NVARCHAR(MAX),@RecordCount INT
SET @sql = 'SELECT COUNT(ORDERID) FROM Orders';
CREATE TABLE #T(TID INT);
INSERT INTO #T EXEC(@sql);
SET @RecordCount = (SELECT TID FROM #T)
SELECT @RecordCount
DROP TABLE #T2

2.sp_executesql的使用

sp_executesql命令在SQL Server中引入的比EXEC命令晚一些,它主要为重用执行计划提供更好的支持。

为了和EXEC作一个鲜明的对比,我们看看如果用代码1的代码,把EXEC换成sp_executesql,看看是否得到我们所期望的结果

代码

DECLARE @TableName VARCHAR(50),@sql NVARCHAR(MAX),@OrderID INT ,@sql2 NVARCHAR(MAX);
SET @TableName = 'Orders ';
SET @OrderID = 10251;
SET @sql = 'SELECT * FROM '+QUOTENAME(@TableName) + ' WHERE OrderID = '+CAST(@OrderID AS VARCHAR(50)) + ' ORDER BY ORDERID DESC'
EXEC sp_executesql @sql

注意最后一行;事实证明可以运行;

sp_executesql提供接口

sp_executesql命令比EXEC命令更灵活,因为它提供一个接口,该接口及支持输入参数也支持输出参数。这功能使你可以创建带参数的查询字符串,这样就可以比EXEC更好的重用执行计划,sp_executesql的构成与存储过程非常相似,不同之处在于你是动态构建代码。它的构成包括:代码快,参数声明部分,参数赋值部分。说了这么多,还是看看它的语法:

EXEC sp_executesql

@stmt= <statement>,--类似存储过程主体

@params = <params>, --类似存储过程参数部分,声明参数类型

<params assignment> --类似存储过程调用,为参数赋值,参数值要和参数顺序要一一对应,也可以通过为参数指明参数值的方式为其赋值

@stmt参数是输入的动态批处理,它可以引入输入参数或输出参数,和存储过程的主体语句一样,只不过它是动态的,而存储过程是静态的,不过你也可以在存储过程中使用sp_executesql;

@params参数与定义输入/输出参数的存储过程头类似,实际上和存储过程头的语法完全一样;

@<params assignment> 与调用存储过程的EXEC部分类似。

其实@stmt,@params可以省略,那么exec sp_executesql的语法就可以简写成如下格式:

EXEC sp_executesql
<statement>,
<params>,
<params assignment>

为了说明sp_executesql对执行计划的管理优于EXEC,我将使用前面讨论EXEC时用到的代码。

代码

DECLARE @TableName VARCHAR(50),@sql NVARCHAR(MAX),@OrderID INT;
SET @TableName = 'Orders ';
SET @OrderID = 10251;
SET @sql = 'SELECT * FROM '+@TableName + ' WHERE OrderID = @OID ORDER BY ORDERID DESC'
--注意当要对动态sql语句的表名实行参数化时,不可以如下表示:
--set @sql='select * from @TableName where OrderID=@OID ORDER BY Orderid desc',
--如果这样会提示必须声明标量变量@TableName,只可以如上面所写的一样,将表名@TableName作为变量名进行拼接

EXEC sp_executesql
@sql,
N'@OID int ',
@OID = @OrderID

下面我们看看exec sp_executesql的执行效率,在调用该代码和检查它生成的执行计划前,先清空缓存中的执行计划;

DBCC FREEPROCCACHE

将上面的动态代码执行3次,每次执行都赋予@OrderID 不同的值,然后查询sys.syscacheobjects表,并注意它的输出,优化器只创建了一个备用计划,而且该计划被重用的3次

SELECT cacheobjtype,objtype,usecounts,sql FROM sys.syscacheobjects WHERE sql NOT LIKE '%cache%' AND sql NOT LIKE '%sys.%' AND sql NOT LIKE '%sp_executesql%'

点击F5运行。

sq_executesql的另一个与其接口有关的强大功能是,你可以使用输出参数为调用批处理中的变量返回值。利用该功能可以避免用临时表返回数据,从而得到更高效的代码和更少的重新编译。定义和使用输出参数的语法与存储过程类似。也就是说,你需要在声明参数时指定OUTPUT子句。例如,下面的静态代码简单的演示了如何从动态批处理中利用输出参数@p把值返回到外部批处理中的变量@i.

DECLARE @sql AS NVARCHAR(12),@i AS INT;
SET @sql = N' SET @p = 10';
EXEC sp_executesql
@sql,
N'@p AS INT OUTPUT',
@p = @i OUTPUT
SELECT @i --该代码返回输出10

以字母 N 为前缀标识 Unicode 字符串常量

总结以下几点:
一.使用exce sp_executesql效率比exec要高,同一类型的语句,只需编译一次即可,而exec执行几次就需要编译几次。
二.构造动态sql的where子句,也就是条件子句时,exec无法使用变量来进行站位,需要将变量转换成字符串,然后和动态sql进行拼接,这就可能引起Sql注入问题,如下:

SET @sql = 'SELECT * FROM '+QUOTENAME(@TableName) +
' WHERE OrderID = '+CAST(@OrderID AS VARCHAR(50)) + ' ORDER BY ORDERID DESC'

而若使用exec sp_executesql则可以使用变量来进行站位,以后再给这个参数传值的放式构造动态sql,就避免的Sql注入的问题,如下:

SET @sql = 'SELECT * FROM '+@TableName + ' WHERE OrderID = @OID ORDER BY ORDERID DESC'

三.无论是Exec还是Exec sp_executesql,如果想要将表名和列名进行动态参数化,不可以使用表名参数和列名参数来进行站位,而且表名参数和列名参数需要使用存储过程的参数.对 于exec sp_executesql来说,不可以将表名参数和列名参数在指定为在exec sp_executesql参数声明部分声明的参数,如:

代码

create PROCEDURE GetData
@tbName nvarchar(10),
@colName nvarchar(10),
@Name nvarchar(10)
AS
BEGIN
declare @sql nvarchar(50);
set @sql='select '+ @colName+' from ' +@tbName+ ' where name=@whereName';
--注意此句不可以写成如下:
-- set @sql='select @colName from @tbName where name=@whereName';
exec sp_executesql
@sql,
N'@whereName nvarchar(10)',
@Name
END

也就是说exec sp_executesql语句的参数声明部分只能声明动态sql的where子句的参数。

9. 如何获取存储过程中执行的SQL语句

如果你的数据库是微软公司的SQL Server,则可以使用如下命令查看存储过程的T-SQL语句:

use your_db_nameGOEXEC sp_helptext N'your_stored_procere_name';GO