如何在大量数据库中删除过程 (SQL Server 2016)

Sae*_*ati 0 sql-server stored-procedures cursors sql-server-2016

我有一个简单的过程,存在于 150 多个数据库中。我可以将它们一一删除,这是软件开发界最愚蠢的工作。或者我可以以某种方式在一个查询中动态删除它们,这很聪明但不起作用。

我试过了:

execute sp_msforeachdb 'drop procedure Usages'
Run Code Online (Sandbox Code Playgroud)

我有:

无法删除过程“用法”,因为它不存在或您没有权限。

所以我想也许我为它创建了一个游标。于是我写道:

declare @command nvarchar(max) = '
drop procedure Usages
';
declare @databaseName nvarchar(100)
declare databasesCursor cursor for select [name] from sys.databases where database_id > 5
open databasesCursor
fetch next from databasesCursor into @databaseName
while @@fetch_status = 0
begin
    print @databaseName
    execute sp_executesql @command
    fetch next from databasesCursor into @databaseName
end
close databasesCursor
deallocate databasesCursor
Run Code Online (Sandbox Code Playgroud)

再次,我收到了同样的消息。我想,也许它不会改变数据库的上下文,因此我在删除命令前面加上了给定数据库的名称,所以命令会变得类似于drop procedure [SomeDatabase].dbo.Usages,但后来我收到了:

“DROP PROCEDURE”不允许将数据库名称指定为对象名称的前缀。

所以,我想出动态执行,use @databaseName以便我可以在该数据库的上下文中删除过程。但它不起作用。我该怎么办?我被困在聪明的方法上,而且我现在比愚蠢的方法花费的时间更多。

Yan*_*ens 5

你很亲近,但忘记了一件小事:

execute sp_msforeachdb 'USE [?] drop procedure Usages'
Run Code Online (Sandbox Code Playgroud)

使用 [?] 实际上会转到每个数据库,并在那里执行它,这应该可以解决您的问题。
但是,您可以添加一些内容,在删除该过程之前首先检查该过程是否存在,因为现在如果数据库中不存在该过程,您仍然会收到错误消息。

编辑:一个更干净的版本是这样的:

DECLARE @SQL NVARCHAR(MAX)

SET @SQL = '
USE [?]
IF EXISTS ( SELECT  *
            FROM    sys.objects
            WHERE   object_id = OBJECT_ID(N''Usages'')
                    AND type IN ( N''P'', N''PC'' ) ) 
drop procedure Usages
'

EXEC sp_MSforeachdb @SQL
Run Code Online (Sandbox Code Playgroud)

它会在删除之前检查它是否存在,所以如果有这样的 sp,它不会给你错误。

EDIT2:ElliotMajor 发表了评论

我会注意到 sp_msforeachdb 没有记录,不应使用。大量已知错误

他是对的。对于您现在正在做的事情,它应该没问题,但是如果您需要将其放入某些生产代码中,则此 sp 有几个替代品。

改进版本:Spaghetti DBAAaron Bertrand