如何在循环中使用动态查询汇总多客户数据库的单值结果?
跨客户数据库查询结果汇总到临时表解决方案
你脚本里的核心错误是用exec @firstResult = (@firtsQuery)这种方式赋值——EXEC返回的是SQL语句的执行状态码(0表示成功,非0是错误),根本不是查询返回的count数值。下面给两种可行的解决办法:
方案一:用sp_executesql获取输出参数
通过系统存储过程sp_executesql可以定义输出参数,把查询结果直接赋值到变量中,再插入临时表:
DECLARE c_db_names CURSOR FOR SELECT name FROM sys.databases WHERE name NOT IN('master', 'model','msdb','tempdb') DECLARE @db_name NVARCHAR(150) DECLARE @ServerName NVARCHAR(50) = @@SERVERNAME CREATE TABLE #temp_tb( [serverName] [varchar](50) NULL, [tenantCode] [varchar](10) NULL, [value1] [varchar](10) NULL, [value2] [varchar](10) NULL ) OPEN c_db_names FETCH c_db_names INTO @db_name WHILE @@Fetch_Status = 0 BEGIN DECLARE @firstQuery NVARCHAR(MAX) DECLARE @secondQuery NVARCHAR(MAX) DECLARE @firstResult NVARCHAR(10) DECLARE @secondResult NVARCHAR(10) -- 构造查询语句,用sp_executesql的输出参数接收结果 SET @firstQuery = N'SELECT @output = COUNT(*) FROM [' + @db_name + N'].[dbo].table1 WHERE ...' SET @secondQuery = N'SELECT @output = COUNT(*) FROM [' + @db_name + N'].[dbo].table2 WHERE ...' -- 执行并获取第一个结果 EXEC sp_executesql @firstQuery, N'@output NVARCHAR(10) OUTPUT', @output = @firstResult OUTPUT -- 执行并获取第二个结果 EXEC sp_executesql @secondQuery, N'@output NVARCHAR(10) OUTPUT', @output = @secondResult OUTPUT INSERT INTO #temp_tb (serverName, tenantCode, value1, value2) VALUES (@ServerName, @db_name, @firstResult, @secondResult) FETCH c_db_names INTO @db_name END CLOSE c_db_names DEALLOCATE c_db_names SELECT * FROM #temp_tb DROP TABLE #temp_tb
方案二:直接构造INSERT INTO动态SQL(更简洁)
不需要中间变量,直接把查询结果和服务器名、库名一起插入临时表,代码更简洁高效:
DECLARE c_db_names CURSOR FOR SELECT name FROM sys.databases WHERE name NOT IN('master', 'model','msdb','tempdb') DECLARE @db_name NVARCHAR(150) DECLARE @ServerName NVARCHAR(50) = @@SERVERNAME CREATE TABLE #temp_tb( [serverName] [varchar](50) NULL, [tenantCode] [varchar](10) NULL, [value1] [varchar](10) NULL, [value2] [varchar](10) NULL ) OPEN c_db_names FETCH c_db_names INTO @db_name WHILE @@Fetch_Status = 0 BEGIN DECLARE @insertSql NVARCHAR(MAX) -- 直接构造INSERT语句,把两个查询的结果作为字段值插入 SET @insertSql = N'INSERT INTO #temp_tb (serverName, tenantCode, value1, value2) SELECT ''' + @ServerName + N''', ''' + @db_name + N''', (SELECT COUNT(*) FROM [' + @db_name + N'].[dbo].table1 WHERE ...), (SELECT COUNT(*) FROM [' + @db_name + N'].[dbo].table2 WHERE ...)' EXEC sp_executesql @insertSql FETCH c_db_names INTO @db_name END CLOSE c_db_names DEALLOCATE c_db_names SELECT * FROM #temp_tb DROP TABLE #temp_tb
注意事项
- 如果数据库名可能包含特殊字符(比如空格、连字符),用
QUOTENAME(@db_name)代替[' + @db_name + ']更安全,避免语法错误。 - 两个方案都用
sp_executesql替代直接EXEC,是因为它支持参数化,能避免SQL注入风险(虽然这里是内部库名,但养成好习惯很重要)。
内容的提问来源于stack exchange,提问作者Ricky Bounce
相关产品推荐
相关产品推荐

