SQL中 exec sp_executesql 执行 where in 参数方法

本文介绍了解决FastReport报表插件中使用参数批量查询记录的问题,通过修改SQL执行语句并使用declare变量方法成功实现多记录编号的查询。

在公司项目中,需要用到一个方法,就是批量传入记录编号 通过 where jlbh in()的方法查询记录;

平时直接用 select * from  JDZS where Jlbh in(‘001’,‘002’,‘003’) 完全没有问题。

但是我在用到的Fastreport报表插件中,会使用参数传入查询条件来执行SQL语句,原SQL语句“select Jlbh from  JDZS where Jlbh in(''+@jlbhStr+'')”加上参数就变成:

exec sp_executesql N'select * from  JDZS where Jlbh in(@Jlbh)',N'@Jlbh nvarchar(50)',@Jlbh='2018090701016' 

以上方法中,如果参数@Jlbh 传入多个记录编号,就会出现查询无结果。

通过以下几种方法都试过,要么无结果,要么参数中只能传入一个记录编号,要么就在FastRepot中报错;

 --方法一
exec sp_executesql N'select Jlbh as 记录编号,QbBh as 气表编号 from JDZS  where  Jlbh in (''+@jlbhStr+'')',N'@jlbhStr varchar(95)',@jlbhStr='''2018090701016'''
 --方法二
 exec sp_executesql N'exec(''select Jlbh from  JDZS where Jlbh in(''''''+@jlbhStr+'''''')'')',N'@jlbhStr nvarchar(4000)',@jlbhStr=N'2018090701016'
 --方法三
 exec sp_executesql N'exec(''select Jlbh from  JDZS where Jlbh in(''''+@jlbhStr+'''')'')',N'@jlbhStr nvarchar(4000)',@jlbhStr=N'''2018090701016'''

 --方法四
 exec sp_executesql N'exec(''select * from  JDZS where Jlbh in(''+@jlbhStr+'')'')',N'@jlbhStr nvarchar(4000)',@jlbhStr=N'''2018090701016'',''2018090701015'''


--只有方法四能够执行成功,但是把其中的exec(''select * from  JDZS where Jlbh in(''+@jlbhStr+'')'') 放入 FastReport中要报错;

网上找了一篇相似的问题:

同时按照这个方法执行后还是查询无结果。

但是看到最终的答案就是相当于把第一个回答中的内容改变了方式执行。于是就想到了替换的方式。既然

exec('select Jlbh from  JDZS where Jlbh in('+@jlbhStr+')') 是能够被执行的。那就把这句话放入sp_executesql 中执行,把单引号部分用双引号替换一下。

最终exec 执行的语句就是:

--通过exec  declare变量方法执行是可行的;

declare @sqlids NVARCHAR(4000)
set @sqlids='''2018090701016'',''2018090701015''' 
exec('select * from JDZS where Jlbh in (' + @sqlids + ')')

--将sp_executesql 中可执行的sql查询语句
 exec sp_executesql N'exec(''select * from  JDZS where Jlbh in(''+@jlbhStr+'')'')',N'@jlbhStr nvarchar(4000)',@jlbhStr=N'''2018090701016'',''2018090701015'''

--替换为 执行exec体:

exec sp_executesql N' declare @sqlids NVARCHAR(4000)
set @sqlids=@jlbhStr 
exec(''select * from JDZS where Jlbh in ('' + @sqlids + '')'')',N'@jlbhStr nvarchar(4000)',@jlbhStr=N'''2018090701013'',''2018090701012'''

当执行参数  @jlbhStr=N'''2018090701016'',''2018090701015'''  的时候就可以查询出想要的结果;而我最终要的就是sp_executesql(' ')中的部分,

所以最终的语句就是把原来的“ select Jlbh from  JDZS where Jlbh in(''+@jlbhStr+'')” 替换为:

declare @sqlids NVARCHAR(4000)
set @sqlids=@jlbhStr 
exec('select * from JDZS where Jlbh in (' + @sqlids + ')')

实际传入的参数变量的字符按照平时SQL中的 where in方法即可:set @jlbhStr='''2018090701016'',''2018090701015''';

 

### SQL Server 中 `sp_executesql` 执行速度不稳定的原因及解决方案 #### 原因分析 1. **执行计划缓存问题** `sp_executesql` 的一个主要优势是支持参数化查询,这使得 SQL Server 可以缓存已编译的执行计划以供重复使用。然而,如果动态 SQL 语句中的参数值导致不同的执行计划被生成,SQL Server 可能会频繁地重新编译执行计划,从而影响性能[^1]。 2. **参数嗅探(Parameter Sniffing)** 参数嗅探是指 SQL Server 在第一次执行查询时会根据传入的参数值选择最优的执行计划,并将其缓存。当后续使用不同参数值调用时,可能因为缓存的执行计划不再是最优而导致性能下降。这种现象在数据分布不均匀的情况下尤为明显[^3]。 3. **资源竞争** 如果系统中存在大量并发的 `sp_executesql` 调用,可能会导致锁、闩锁或内存资源的竞争,从而影响执行速度。此外,长时间运行的查询可能会占用大量内存或 CPU 资源,进一步加剧性能问题[^4]。 4. **统计信息过期或不准确** SQL Server 的查询优化器依赖于表和索引的统计信息来生成执行计划。如果统计信息过期或不准确,优化器可能会选择次优的执行计划,导致查询性能不稳定[^2]。 5. **动态 SQL 本身的复杂性** 动态 SQL 的复杂性可能导致生成的执行计划不够优化。例如,字符串拼接错误、缺少索引提示或不当的参数化都可能导致性能问题[^4]。 --- #### 解决方案 1. **强制重新编译执行计划** 使用 `OPTION (RECOMPILE)` 提示可以强制 SQL Server 每次执行查询时都重新编译执行计划。这种方法适用于参数嗅探问题较为严重的情况,但需要注意的是,频繁的重新编译可能会增加 CPU 开销。 ```sql EXEC sp_executesql N'SELECT * FROM Person.Person WHERE BusinessEntityID = @ID OPTION (RECOMPILE)', N'@ID INT', @ID = 17; ``` 2. **使用局部变量避免参数嗅探** 将输入参数赋值给局部变量后,再在查询中使用局部变量,可以有效避免参数嗅探问题。这是因为局部变量的值不会被优化器感知,从而避免了缓存的执行计划对特定参数值的过度优化。 ```sql DECLARE @LocalID INT; SET @LocalID = @ID; EXEC sp_executesql N'SELECT * FROM Person.Person WHERE BusinessEntityID = @LocalID', N'@LocalID INT', @LocalID = @LocalID; ``` 3. **更新统计信息** 定期更新表和索引的统计信息,确保查询优化器能够生成最优的执行计划。可以使用以下命令手动更新统计信息: ```sql UPDATE STATISTICS TableName WITH FULLSCAN; ``` 4. **优化动态 SQL 语句** 确保动态 SQL 语句尽可能简单且高效。例如,避免不必要的字符串拼接,合理使用索引提示,并确保查询条件明确且符合实际需求[^4]。 5. **监控和调整资源分配** 使用 SQL Server Profiler 或 Extended Events 监控 `sp_executesql` 的执行情况,识别潜在的资源瓶颈。根据监控结果,调整系统配置(如内存分配、CPU 优先级等)以提高性能。 6. **清理缓存中的旧执行计划** 如果发现某些执行计划导致性能问题,可以手动清除缓存中的执行计划以强制重新生成新的计划。注意,此操作可能会影响其他查询的性能。 ```sql DBCC FREEPROCCACHE; ``` --- ### 示例代码 以下是一个结合上述解决方案的完整示例: ```sql DECLARE @Sql NVARCHAR(MAX), @ID INT; SET @ID = 17; -- 使用局部变量避免参数嗅探 DECLARE @LocalID INT; SET @LocalID = @ID; SET @Sql = N' SELECT * FROM Person.Person WHERE BusinessEntityID = @LocalID OPTION (RECOMPILE);'; EXEC sp_executesql @Sql, N'@LocalID INT', @LocalID = @LocalID; ``` ---
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值