我正在编写一个动态查询,它将大量视图和存储过程从一个数据库复制到另一个数据库。我无法使用本机 SSMS 功能,因为这将从 Web 前端驱动。有许多可能的源数据库和目标数据库:
DECLARE @TargetDatabase nvarchar(20) = 'DatabaseA'
DECLARE @Query nvarchar(MAX)
SET @Query = 'USE [' + @TargetDatabase + ']' + CHAR(10) + 'GO' + CHAR(10) + 'CREATE VIEW dbo.ViewA AS SELECT 1 FROM dbo.[TableA]'
EXEC(@Query)
--PRINT @Query
我如何填充 @Query 变量比上面复杂得多,但就这个问题而言,这应该足够了。
如果没有“GO”来分隔两个批次,我会收到错误消息“'CREATE VIEW'必须是查询批次中的第一个语句”
当我添加“GO”时,我收到该错误消息,但我也收到“'GO'附近的语法不正确。”
如果我打印 @Query,将结果复制/粘贴到 SSMS,它可以正常工作。
我能想到的最好的结果是它失败了,因为它不喜欢“GO”之前的 CHAR(10)。
想法?
GO
不是 SQL 关键字。它是由 SSMS 等工具解释的批次分隔符,以便在单个文件中分隔批次。
在动态 SQL 中,要分隔批次,您需要多次实际使用
EXEC
。
但是
USE
不能跨批次工作。正确的方法是调用 Otherdb.sys.sp_executesql
。如果数据库名称本身是动态的,那么您可以在变量中构造该过程名称并执行 EXEC @proc @query...
。
您还应该使用
QUOTENAME
来正确引用名称。
DECLARE @TargetDatabase sysname = 'DatabaseA';
DECLARE @Query nvarchar(MAX) = '
CREATE VIEW dbo.ViewA
AS
SELECT 1
FROM dbo.TableA;
';
DECLARE @proc nvarchar(1000) = QUOTENAME(@TargetDatabase) + '.sys.sp_executesql';
PRINT @Query -- your friend
EXEC @proc @Query;