如何在SQL Server中用脚本将动态SELECT结果赋值给变量并执行
在SQL Server中嵌套执行动态SQL的实现方案
核心思路
无法直接通过EXEC(EXEC(SQL))实现嵌套执行,需要先将动态生成的多条IF ELSE-INSERT语句合并为单个字符串变量,再执行。以下提供两种可行方案:
方案1:借助表变量中转存储
先执行生成语句的动态SQL,将结果存入表变量,再合并为最终执行字符串:
-- 1. 定义生成IF ELSE语句的动态SQL(示例SQL1) DECLARE @SQL1 NVARCHAR(MAX) = N' SELECT CASE WHEN EXISTS(SELECT 1 FROM Policy WHERE PolicyNo = s.PolicyNo) THEN N''IF EXISTS(SELECT 1 FROM Policy WHERE PolicyNo = ''''' + s.PolicyNo + ''''''') BEGIN PRINT ''''Policy ''''' + s.PolicyNo + ''''' already exists'''' END ELSE BEGIN INSERT INTO Policy(PolicyNo, Amount) VALUES(''''' + s.PolicyNo + ''''', ' + CAST(s.Amount AS NVARCHAR(20)) + ') END'' END AS DynamicStmt FROM SourcePolicyTable s '; -- 2. 定义表变量存储生成的单条语句 DECLARE @TempStmts TABLE (Stmt NVARCHAR(MAX)); -- 执行SQL1,将结果插入表变量 INSERT INTO @TempStmts(Stmt) EXEC sp_executesql @SQL1; -- 3. 合并所有语句到@SQL2 DECLARE @SQL2 NVARCHAR(MAX) = N''; SELECT @SQL2 += Stmt + CHAR(13) + CHAR(10) -- 加换行符提升可读性 FROM @TempStmts; -- 4. 执行最终动态SQL EXEC sp_executesql @SQL2;
方案2:在动态SQL内部直接合并语句(推荐)
利用STRING_AGG(SQL Server 2017+)或XML PATH(兼容旧版本)在动态SQL内部完成语句合并,通过输出参数赋值给变量:
适用于SQL Server 2017及以上版本
DECLARE @SQL1 NVARCHAR(MAX) = N' SELECT @MergedStmt = STRING_AGG( CASE WHEN EXISTS(SELECT 1 FROM Policy WHERE PolicyNo = s.PolicyNo) THEN N''IF EXISTS(SELECT 1 FROM Policy WHERE PolicyNo = ''''' + s.PolicyNo + ''''''') BEGIN PRINT ''''Policy ''''' + s.PolicyNo + ''''' already exists'''' END ELSE BEGIN INSERT INTO Policy(PolicyNo, Amount) VALUES(''''' + s.PolicyNo + ''''', ' + CAST(s.Amount AS NVARCHAR(20)) + ') END'' END, CHAR(13) + CHAR(10) ) FROM SourcePolicyTable s; '; DECLARE @SQL2 NVARCHAR(MAX); -- 执行SQL1,将合并后的语句通过输出参数赋值给@SQL2 EXEC sp_executesql @SQL1, N'@MergedStmt NVARCHAR(MAX) OUTPUT', @MergedStmt = @SQL2 OUTPUT; -- 执行最终动态SQL EXEC sp_executesql @SQL2;
适用于SQL Server 2016及以下版本
DECLARE @SQL1 NVARCHAR(MAX) = N' SELECT @MergedStmt = STUFF( (SELECT CHAR(13) + CHAR(10) + CASE WHEN EXISTS(SELECT 1 FROM Policy WHERE PolicyNo = s.PolicyNo) THEN N''IF EXISTS(SELECT 1 FROM Policy WHERE PolicyNo = ''''' + s.PolicyNo + ''''''') BEGIN PRINT ''''Policy ''''' + s.PolicyNo + ''''' already exists'''' END ELSE BEGIN INSERT INTO Policy(PolicyNo, Amount) VALUES(''''' + s.PolicyNo + ''''', ' + CAST(s.Amount AS NVARCHAR(20)) + ') END'' END FROM SourcePolicyTable s FOR XML PATH(''''), TYPE ).value(''.'', ''NVARCHAR(MAX)''), 1, 2, ''''); '; DECLARE @SQL2 NVARCHAR(MAX); EXEC sp_executesql @SQL1, N'@MergedStmt NVARCHAR(MAX) OUTPUT', @MergedStmt = @SQL2 OUTPUT; EXEC sp_executesql @SQL2;
关键注意事项
- 优先使用
sp_executesql而非原生EXEC,支持参数传递和输出变量,避免SQL注入风险 - 合并语句时添加
CHAR(13)+CHAR(10)换行符,方便调试和语句可读性
内容的提问来源于stack exchange,提问作者Ramya
相关产品推荐
相关产品推荐

