循环遍历所有 SSMS 数据库而不重新创建存储过程

Posted

技术标签:

【中文标题】循环遍历所有 SSMS 数据库而不重新创建存储过程【英文标题】:Loop Through All SSMS Databases without Recreating Stored Procedure 【发布时间】:2021-04-14 21:29:57 【问题描述】:

背景信息:

在 Python 中,如果我想将相同的逻辑应用于列表中的不同值,我可能会编写类似这样的代码。

database_list = ["db_1", "db_2", "db_3"]

for x in range(0,len(database_list),1):
     
     print("the database name is " + database_list[x])

我想做的事:

我在 SSMS 中尝试做的是为每个数据库提取数据库对象列表。我创建了一个存储过程来准确提取我想要的内容,但我必须针对每个数据库运行它,所以 10 个数据库意味着运行 10 次。

我的目标是使用 T-SQL 查询而不是 Python。

我试着做这样的事情:

 exec sp_MSforeachdb 'USE ?; EXEC [dbo].[my_stored_procedure]';

问题在于,[dbo].[my_stored_procedure] 必须存在于我想要在其中执行此操作的每个数据库中。

如何在 1 个数据库中创建存储过程,但对所有数据库或我选择的数据库列表执行它?

【问题讨论】:

您能否详细说明您要解决的问题。 我正在尝试在 SSMS 中实现“FOR LOOP”逻辑,以针对所有数据库从 1 个数据库运行 1 个存储过程。 这就是你想要做的,不是你想要解决的问题 实现我想要做的就是我想要解决的问题。 所以您需要一个动态 SQL,因为您认为(想象一下,如果您是 DBMS)SQL Server 将如何知道您在不指定数据库的情况下访问什么对象?过程不仅仅是传递的一些文本,它采用目标上下文。为此,您需要编写代码块而不是过程 【参考方案1】:

我知道你想要做什么,如果这是我认为(你似乎不愿意实际说出来!)你可以执行以下操作:

master 数据库中,创建您的过程。通常你不会这样做,但在这种情况下你必须给它添加前缀sp_

use master
go
create procedure sp_testproc as

select top 10 * from sys.tables
go

现在,如果您运行它,它将从 master 数据库返回表。

如果您将上下文切换到另一个数据库和exec master.dbo.sp_testproc,它仍会从主数据库返回表。

master,运行

sys.sp_MS_marksystemobject sp_testproc

现在将上下文切换到不同的数据库和exec master.dbo.sp_testproc

它将从您正在使用的数据库中返回表。

【讨论】:

我不知道我可以使我想做的事情看起来更清晰。我觉得我解释得很好。有时我会与不阅读超过 50 个单词的人一起工作,我相信这可能就是其中一种情况。无论如何,我感谢你试图帮助我。 让我玩你给我的东西,我会回来陪你的。谢谢! 我有点理解你的问题,因为我对一些全局维护类型的工作做的完全一样 - 只是解释你的程序需要在所选数据库的上下文中运行是真的。 当我输入“如何在 1 个数据库中创建存储过程,但对所有数据库或我选择的数据库列表执行它?”时,我以为我做到了。在我原来的帖子中大声笑。 当然 - 但请记住,只有您知道您的意思。例如,您可以在任何仅打印“hello world”的数据库中创建一个过程并从任何其他数据库运行它,它会工作得很好——但这不是您要寻找的:)【参考方案2】:

尝试在 master 中创建你的 sproc 并使用 sp_ 前缀命名它:

USE master
GO

CREATE PROCEDURE sp_sproc_name
AS
 BEGIN
 ...
 END
GO

-- You *may* need to mark it as a system object
EXEC sys.sp_MS_marksystemobject sp_sprocname

见:https://nickstips.wordpress.com/2010/10/18/sql-making-a-stored-procedure-available-to-all-databases/

它应该在所有数据库中都可用

【讨论】:

【参考方案3】:

在 Master 数据库中创建带有 sp_ 前缀的存储过程,并在存储过程中使用动态 SQL,以便它解析相对于当前数据库而不是包含存储过程的数据库的对象名称。

EG

use master 
go
CREATE OR ALTER  PROCEDURE [dbo].[sp_getobjects]
AS
exec ('
     select *
     from [sys].[objects]
     where is_ms_shipped = 0
     order by type, name
     ')
go

use AdventureWorks2017
exec sp_getobjects 

【讨论】:

【参考方案4】:

@LunchBox - 这是您的单个存储过程(您在一个数据库中创建)实际上需要包含“exec sp_MSforeach ....”命令,而不是要执行的命令是“EXEC” ,它必须是您要放入存储过程的实际 SQL。

例如。 (在您的单个存储过程中)

EXEC sp_MSforeachdb 'USE ?; SELECT * FROM <table>; UPDATE <another table> SET ...';

把存储过程(你放入一个数据库)想象成与你的 Python 代码文件没有什么不同——如果你真的想在 Python 中实现同样的事情,你要么需要在每个数据库,或者在 Python 中构建 SQL 语句字符串并针对每个数据库执行它。

我了解您认为使用 SQL 可以实现的目标,但存储过程确实无法按您预期的方式工作。即使您在不同数据库的上下文中,但您运行 EXEC .stored_proc,该存储过程最终也会在它所在的数据库的上下文中运行(而不是您的上下文数据库)。

现在,您可能遇到的唯一一个问题是标准 sp_MSforeachdb 存储过程对可以执行的命令有 2000 个字符的限制(尽管它确实有多个“命令”参数,但这可能不是如果您计划运行一个非常大的代码块,可能会带有贯穿始终的变量,这很实用)。如果这可能会影响您打算做的事情,您可以在线搜索“sp_MSforeachdb 替代方案” - 人们似乎已经创建了少数命令参数可以包含更大字符串的地方。

【讨论】:

以上是关于循环遍历所有 SSMS 数据库而不重新创建存储过程的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server 索引重新创建存储过程慢

For循环将列表的所有元素放入不同的文本文件中,而不是在python中遍历每个元素

mysql存储过程之循环遍历查询结果集

时间循环 - 将矢量数据存储在文件中而不覆盖

使用 SSMS 删除了本地数据库表,无法使用 ASP.NET Entity Framework 重新创建它

csharp 循环遍历两个列表,检查条件,创建新的db对象实例(记录),保存到db以及运行存储过程。