在单个SQL Server实例中,我有以下数据库:
...
在每个分支DB中都有一个名为usp_ComputeDailySales
的过程,它执行一些计算并将每日销售数据写入Headquarters
数据库。如何在Headquarters DB中编写单个存储过程以在所有分支DB中执行usp_ComputeDailySales
?
我可以写下面的代码,但我认为这不是可行的方法。
USE Branch001
EXEC usp_ComputeDailySales
USE Branch002
EXEC usp_ComputeDailySales
...
我想要一些方法同时为所有分支DB执行该过程。
答案 0 :(得分:2)
这不是动态SQL,而是依赖于延迟名称解析等。
EXECUTE,请参阅@module_name_var
参数
DECLARE @sql varchar(300)
SELECT
[name] + '..usp_ComputeDailySales' AS Cmd
INTO #List
FROM
sys.databases d WHERE d.[name] LIKE 'branch%'
OR --Thanks Mitch
d.[name] = 'Headquarters'
WHILE EXISTS (SELECT * FROM #List)
BEGIN
SELECT TOP 1 @SQL = Cmd FROM #List
EXEC @SQL
DELETE #List WHERE Cmd = @SQL
END
在KM的评论之后编辑
是的,有区别但我会澄清:
EXEC(@SQL)表示@SQL可以是“SELECT * FROM foo
”或“DELETE User WHERE 1=1'
;.”
EXEC @SQL表示@SQL是一个对象名。所以我应该使用@Obj
所以,你可以这样做:
DECLARE @Obj varchar(200)
SELECT @Obj = 'dbo.uspCustomHook'
IF OBJECT_ID(@Obj) IS NOT NULL
EXEC @Obj @p1 = 1, @p2 = 'bob', ...
它避免了延迟名称解析错误。编译批处理/ proc时,如果dbo.uspCustomHook不存在则没有错误。
自从SQL 2000以来我没有使用过这种技术,我不知道SQL 2005(语句级别重新编译)是否足够聪明,如果应该运行@Obj,因为它不存在,所以它不会尝试编译EXEC语句......
它对于跨数据库,相同的实例查询也很有用。您可以在不依赖链接服务器或硬编码数据库名称的情况下配置prd-prod,dev-dev等。
答案 1 :(得分:0)
您可以使用名为sp_MSforeachdb
的未记录的存储过程答案 2 :(得分:0)
只需使用完全限定的名称来解决这些问题,例如:
<Database Name>.<owner>.<table>
并替换值。
示例:CustomerDatabase.dbo.Users
在你的情况下,它看起来像这样:
exec Branch001.dbo.usp_ComputeDailySales
exec Branch002.dbo.usp_ComputeDailySales
exec Branch003.dbo.usp_ComputeDailySales
这假定一个用户拥有所有这些数据库的权限。
答案 3 :(得分:0)
您可以使用sp_msForEachDB轻松完成此操作。这里的第一个示例将在名为LIKE'Cranch%'的每个数据库上运行proc:
EXECUTE sp_msForEachDB '
IF ''?'' like ''Branch%''
BEGIN
USE ?
EXECUTE usp_ComputeDailySales
END
'
这个将在包含该名称的存储过程的每个数据库(无论名称)上运行它:
EXECUTE sp_msForEachDB '
USE ?
IF object_id(''usp_ComputeDailySales'') is not null
EXECUTE usp_ComputeDailySales
'
喋喋不休地对它们大惊小怪 - 它们起作用,但它们需要一点时间习惯。
附录:虽然这是一个“未记录的功能”,但它是自SQL Server 7.0以来可能更早的版本。有许多文章和样本使用它,可能有许多依赖它的企业系统,其中一些是我建立的。我真的从来没有遇到过任何问题(一旦我得到了它们,而且双重正确,那就是。)