0

0

exec 与 exec sp_executesql 的用法及比较[通俗易懂]

爱谁谁

爱谁谁

发布时间:2025-07-09 12:24:31

|

652人浏览过

|

来源于php中文网

原创

大家好,又见面了,我是你们的朋友全栈君。

本文将详细介绍如何使用 execexec sp_executesql 来执行动态SQL,并对它们进行比较。

(下面用到的数据库表来自SQLSERVER 的示例数据库 AdventureWorks2008)

一、execexec sp_executesql 的用法

  1. 动态SQL(使用字符串拼接的方式)
declare @FName2 varchar(20) = 'Ken', @PeronType varchar(10) = 'GC', @sql nvarchar(1000);
-- 不推荐这样使用
exec('select * from Person.Person where FirstName =''' + @FName2 + ''' and PersonType= ''' + @PeronType + '''')
-- sp_executesql 不能接收含有变量拼接的sql字符串。下面的sql执行会报错
-- exec sp_executesql 'select * from Person.Person where FirstName =''' + @FName2 + ''' and PersonType= ''' + @PeronType + ''''
-- 不推荐这样使用:无法防止SQL注入,无法重用执行计划,拼接麻烦且容易出错(字符串类型的需要单引号括起来)
set @sql =  'select * from Person.Person where FirstName =''' + @FName2 + ''' and PersonType= ''' + @PeronType + ''''
exec sp_executesql @sql
  1. 带有输入参数时的使用
declare @FName2 varchar(20) = 'Ken', @PeronType varchar(10) = 'GC', @sql nvarchar(1000);
-- 推荐先使用变量存放拼接的sql,再使用exec执行sql
set @sql =  'select * from Person.Person where FirstName =''' + @FName2 + ''' and PersonType= ''' + @PeronType + ''''
exec(@sql)
-- 推荐这样使用(可以防止SQL注入,可以重用执行计划)
-- 此处输入参数要加上N,不然会报错:过程需要类型为 'ntext/nchar/nvarchar' 的参数 '@params
set @sql = 'select * from Person.Person where FirstName =@FName and PersonType=@PersonType'
exec sp_executesql @sql, N'@FName varchar(20), @PersonType varchar(10)', @FName2, @PeronType

注:exec 只能使用拼接字符串的方式,不支持使用输入参数,而且执行计划不能重用。因此,一般情况下,推荐使用 exec sp_executesql 的方式,而不是 exec

  1. 带有输入参数时的使用
declare @sql nvarchar(1000), @cnt int = -1;
-- 使用 exec
-- exec sql内无法访问sql之外定义的变量,直接使用下面的会报错: 必须声明变量 "@cnt"。外部也无法访问到 exec sql里定义的变量
--无法直接将值传出,只能通过select 变量/insert into exec等方式看到值
--exec('select @cnt=count(1) from Person.Person; select @cnt')
exec('declare @cnt int; select @cnt=count(1) from Person.Person')
print @cnt  -- -1, 无法访问 exec 里取到的  @cnt 的值
set @sql = 'select @cnt=count(1) from Person.Person'
exec sp_executesql @sql, N'@cnt int output', @cnt output --此处必须加上ouput,不然无法取到值
print @cnt
  1. 带有输入输出参数时的使用
declare @sql nvarchar(1000), @cnt int = -1, @FName varchar(20) = 'Ken';
exec('declare @cnt int; select @cnt=count(1) from Person.Person where FirstName = ''' + @FName + ''';  select @cnt')
print @cnt  -- -1
set @sql = 'select @cnt=count(1) from Person.Person where FirstName = @FName'
exec sp_executesql @sql, N'@cnt int output, @FName varchar(20)', @cnt output, @FName --此处必须加上ouput,不然无法取到值
print @cnt
  1. insert into exec/exec sp_executesql 的使用
declare @tmp table (BusinessEntityID int, FirstName varchar(50), LastName varchar(50))
insert into @tmp
exec sp_executesql N'select top 10 BusinessEntityID, FirstName, LastName from Person.Person'
insert into @tmp
exec(N'select top 10 BusinessEntityID, FirstName, LastName from Person.Person')
select * from @tmp

二、execexec sp_executesql 比较

  1. execexec sp_executesql 都可以用于执行动态SQL。

  2. sp_executesql 后面需要直接使用表示拼接后的sql的变量或者sql常量字符串,后面不能直接使用常量+变量拼接的语句。如下面的语句会报错:

declare @FName2 varchar(20) = 'Ken', @PeronType varchar(10) = 'GC', @sql nvarchar(1000);
exec sp_executesql 'select * from Person.Person where FirstName =''' + @FName2 + ''' and PersonType= ''' + @PeronType + ''''

这种情况下,需要先将sql拼凑后的结果放入一个变量中,然后使用 exec sp_executesql 执行;或者使用入参的方式来实现。推荐使用下面的方式:

declare @FName2 varchar(20) = 'Ken', @PeronType varchar(10) = 'GC', @sql nvarchar(1000);
set @sql = 'select * from Person.Person where FirstName = @FName2 and PersonType = @PeronType'
exec sp_executesql @sql, N'@FName varchar(20), @PersonType varchar(10)', @FName2, @PeronType
  1. sp_executesql 要求动态Sql和动态Sql参数列表必须是Nvarchar, 动态Sql的参数列表与外部提供值的参数列表顺序必需一致,且不能使用变量。

  2. exec 查询不能使用sql外面定义的变量,查询的结果也不容易进行使用。而exec sp_executesql 可以使用入参和出参的方式很方便的获取或者返回内容。

  3. sp_executesql 可以建立带参数的查询字符串还可以重用执行计划。通过下面的示例来了解一下。

    InsCode
    InsCode

    InsCode 是CSDN旗下的一个无需安装的编程、协作和分享社区

    下载

首先是 exec

DBCC FREEPROCCACHE  -- 清空执行计划缓存
DECLARE @Sql NVARCHAR(MAX), @ID INT; 
SET @ID = 15; -- 15使用之后,换成10, 12等再次执行
SET @sql = 'SELECT * FROM Person.Person WHERE BusinessEntityID = '+CAST(@ID AS VARCHAR(10))+' ORDER BY BusinessEntityID DESC'
EXEC(@sql); 
SELECT cacheobjtype,objtype,usecounts,sql FROM sys.syscacheobjects WHERE sql NOT LIKE '%cach%' AND sql NOT LIKE '%sys.%'

使用exec 执行三次后,查询到的执行计划缓存如下:

exec 与 exec sp_executesql 的用法及比较[通俗易懂]

通过上面的截图可以看到,执行三次生成了三次执行计划。

下面,来看一下exec sp_executesql

DBCC FREEPROCCACHE
DECLARE @Sql NVARCHAR(MAX), @ID INT; 
SET @ID = 17; 
SET @sql = 'SELECT * FROM Person.Person WHERE BusinessEntityID = @ID ORDER BY BusinessEntityID DESC'
exec sp_executesql @sql, N'@ID int', @ID
SELECT cacheobjtype,objtype,usecounts,sql FROM sys.syscacheobjects WHERE sql NOT LIKE '%cach%' AND sql NOT LIKE '%sys.%'

同样执行三次之后,查询到的执行计划缓存如下:

exec 与 exec sp_executesql 的用法及比较[通俗易懂]

通过上面的截图可以看到,只生成了一次执行计划。

  1. sp_executesql 可以建立带参数的查询字符串可以防止sql注入
-- 下面的SQL注入
DECLARE @Sql NVARCHAR(MAX), @FName varchar(20); 
SET @FName = '''ken'' or 1=1'; 
SET @sql = 'SELECT * FROM Person.Person WHERE FirstName = ' + @FName + ' ORDER BY BusinessEntityID DESC'
exec sp_executesql @sql
--下面的可以防止SQL注入
DECLARE @Sql NVARCHAR(MAX), @FName varchar(20); 
SET @FName = '''ken'' or 1=1'; 
SET @sql = 'SELECT * FROM Person.Person WHERE FirstName = @FName ORDER BY BusinessEntityID DESC'
exec sp_executesql @sql, N'@FName varchar(20)', @FName

发布者:全栈程序员栈长,转载请注明出处:https://www.php.cn/link/3cdc0a294d55c26d6d656877c731d24d 原文链接:https://www.php.cn/link/c8377ad2a50fb65de28b11cfc628d75c

相关专题

更多
数据分析工具有哪些
数据分析工具有哪些

数据分析工具有Excel、SQL、Python、R、Tableau、Power BI、SAS、SPSS和MATLAB等。详细介绍:1、Excel,具有强大的计算和数据处理功能;2、SQL,可以进行数据查询、过滤、排序、聚合等操作;3、Python,拥有丰富的数据分析库;4、R,拥有丰富的统计分析库和图形库;5、Tableau,提供了直观易用的用户界面等等。

683

2023.10.12

SQL中distinct的用法
SQL中distinct的用法

SQL中distinct的语法是“SELECT DISTINCT column1, column2,...,FROM table_name;”。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

322

2023.10.27

SQL中months_between使用方法
SQL中months_between使用方法

在SQL中,MONTHS_BETWEEN 是一个常见的函数,用于计算两个日期之间的月份差。想了解更多SQL的相关内容,可以阅读本专题下面的文章。

348

2024.02.23

SQL出现5120错误解决方法
SQL出现5120错误解决方法

SQL Server错误5120是由于没有足够的权限来访问或操作指定的数据库或文件引起的。想了解更多sql错误的相关内容,可以阅读本专题下面的文章。

1095

2024.03.06

sql procedure语法错误解决方法
sql procedure语法错误解决方法

sql procedure语法错误解决办法:1、仔细检查错误消息;2、检查语法规则;3、检查括号和引号;4、检查变量和参数;5、检查关键字和函数;6、逐步调试;7、参考文档和示例。想了解更多语法错误的相关内容,可以阅读本专题下面的文章。

358

2024.03.06

oracle数据库运行sql方法
oracle数据库运行sql方法

运行sql步骤包括:打开sql plus工具并连接到数据库。在提示符下输入sql语句。按enter键运行该语句。查看结果,错误消息或退出sql plus。想了解更多oracle数据库的相关内容,可以阅读本专题下面的文章。

677

2024.04.07

sql中where的含义
sql中where的含义

sql中where子句用于从表中过滤数据,它基于指定条件选择特定的行。想了解更多where的相关内容,可以阅读本专题下面的文章。

575

2024.04.29

sql中删除表的语句是什么
sql中删除表的语句是什么

sql中用于删除表的语句是drop table。语法为drop table table_name;该语句将永久删除指定表的表和数据。想了解更多sql的相关内容,可以阅读本专题下面的文章。

417

2024.04.29

Java JVM 原理与性能调优实战
Java JVM 原理与性能调优实战

本专题系统讲解 Java 虚拟机(JVM)的核心工作原理与性能调优方法,包括 JVM 内存结构、对象创建与回收流程、垃圾回收器(Serial、CMS、G1、ZGC)对比分析、常见内存泄漏与性能瓶颈排查,以及 JVM 参数调优与监控工具(jstat、jmap、jvisualvm)的实战使用。通过真实案例,帮助学习者掌握 Java 应用在生产环境中的性能分析与优化能力。

19

2026.01.20

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL 教程
PostgreSQL 教程

共48课时 | 7.5万人学习

Git 教程
Git 教程

共21课时 | 2.8万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号