问题描述
我需要帮助来优化此处显示的存储过程。它可以工作,但是当它运行时,它会为每个数据库生成一个选择脚本。我需要存储过程来联合所有选择语句。
有人知道怎么做吗?
SET NOCOUNT ON;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
IF OBJECT_ID('tempdb.dbo.#database') IS NOT NULL
DROP TABLE #database
CREATE TABLE #database
(
id INT IDENTITY PRIMARY KEY,name sysname
)
SET NOCOUNT ON
BEGIN
INSERT INTO #database(name)
SELECT name
FROM master.sys.databases
WHERE name IN (SELECT [DATABASE] COLLATE latin1_General_CI_AS
FROM SETTINGS.DBO.SETTINGS
WHERE [KEY] = 'DB_NAME' AND SETTING = '1' )
ORDER BY name
END
DECLARE @id INT,@cnt INT,@sql NVARCHAR(max),@currentDb sysname;
SELECT @id = 1,@cnt = MAX(id)
FROM #database
WHILE @id <= @cnt
BEGIN
SELECT @currentDb = name
FROM #database
WHERE id = @id
SET @sql = 'select * FROM ' + @currentDb + '.dbo.People'
PRINT @sql
EXEC (@sql);
PRINT '--------------------------------------------------------------------------'
SET @id = @id + 1;
END
DROP TABLE #database
END
解决方法
在循环中构建动态字符串,并且只有在循环完成后才执行它。
WHILE @id <= @cnt BEGIN
SELECT @currentDb = [name]
FROM #database
WHERE id = @id;
SET @sql = @sql + CASE WHEN LEN(@sql) > 0 THEN ' union all ' ELSE '' END
+ 'SELECT * FROM ' + QUOTENAME(@currentDb) + '.dbo.People';
SET @id = @id + 1;
END;
IF len(@sql) > 0 BEGIN
print @sql
exec (@sql);
END;
注意使用 QUOTENAME
来防止 SQL 注入问题 - 即使只是偶然。
我更改了代码并复制并尝试了下面的链接,效果很好。感谢您的帮助。
How do you use a cursor to combine data in a Union All?
DECLARE @sql NVARCHAR(MAX) = N'';
SELECT @sql = @sql +
'UNION ALL SELECT column1 FROM ' + QUOTENAME(name) + '..tableA' + CHAR(10)
FROM sys.databases
WHERE [name] NOT IN ('master','tempdb','model','msdb')
SELECT @sql = STUFF(@sql,1,10,'')
PRINT @sql
EXEC (@sql)