sp_msforeach db - 为什么我们需要使用 USE 关键字

SEa*_*986 8 sql-server stored-procedures

sp_msforeachdb是一个未公开的 sp,旨在针对服务器实例中的每个数据库运行一些 T-SQL。那么,为什么我需要使用USE关键字来做到这一点

EXEC sp_MSForEachDb @command1 = 'SELECT DB_NAME()'
Run Code Online (Sandbox Code Playgroud)

打印sp_MSForEachDb命令对n次运行的数据库名称,其中n是实例上的数据库数。

EXEC sp_MSForEachDb @command1 = 'USE ?; SELECT DB_NAME()'
Run Code Online (Sandbox Code Playgroud)

打印每个数据库的名称。

为什么需要使用USE语句?这种行为不应该是程序中固有的吗?

Aar*_*and 13

该过程不会USE为您执行命令。该过程的工作方式是将?命令中的each 替换为数据库前缀。

如果你运行这个:

USE foodb;
GO
EXEC sys.sp_MSforeachdb N'SELECT * FROM sys.objects;'; 
-- 3,380 total rows on my system
Run Code Online (Sandbox Code Playgroud)

您还将获得许多结果集,它们都显示来自foodb. 您必须以这种方式发出命令,以便在每个单独数据库的上下文中执行命令:

EXEC sys.sp_MSforeachdb N'SELECT * FROM ?.sys.objects;'; 
-- 50,603 total rows on my system
Run Code Online (Sandbox Code Playgroud)

在这种情况下,它将为每个数据库执行您的命令,并?替换为数据库名称:

SELECT * FROM master.sys.objects;
SELECT * FROM tempdb.sys.objects;
...
Run Code Online (Sandbox Code Playgroud)

要调用不支持数据库前缀的系统函数,通常USE首先需要一个命令。一种以不同方式执行此操作的方法可能是:

EXEC sys.sp_MSforeachdb N'SELECT DB_NAME(DB_ID(''?''));';
Run Code Online (Sandbox Code Playgroud)

或者,更简单地说:

EXEC sys.sp_MSforeachdb N'SELECT N''?'';';
Run Code Online (Sandbox Code Playgroud)

它以这种方式工作的一个原因是您可能正在从当前数据库的上下文中执行,因为它有一个您想要与所有数据库相关的静态对象。因此,假设您在其中foodb并创建了此表:

CREATE TABLE dbo.ObjectNameBlacklist
(
  name sysname
);

INSERT dbo.ObjectNameBlacklist(name) VALUES('badword');
Run Code Online (Sandbox Code Playgroud)

您想标识与此表中的名称匹配的任何数据库中的所有对象。所以你可以说:

EXEC sys.sp_MSforeachdb N'SELECT ''?'', name 
  FROM dbo.ObjectNameBlacklist AS onb
  WHERE EXISTS
  (
    SELECT 1 FROM ?.sys.objects WHERE name = onb.name
  );';
Run Code Online (Sandbox Code Playgroud)

您不希望该命令dbo.ObjectNameBlacklist在每个数据库中查找。当然,您可以手动添加前缀,但由于程序的工作方式,您不必这样做。


Eri*_*ing 5

如果您查看, 或其奇怪的朋友的sp_helptext条目sp_MSforeachdbsp_MSforeachtable

EXEC sys.sp_helptext @objname = N'sp_MSforeachdb';
EXEC sys.sp_helptext @objname = N'sp_MSforeachtable';
Run Code Online (Sandbox Code Playgroud)

您会看到它们都只是以下内容的包装器sp_MSforeach_worker

EXEC sys.sp_helptext @objname = N'sp_MSforeach_worker';
Run Code Online (Sandbox Code Playgroud)

他们所做的只是建立一个有效的<list of things>,但他们实际上并没有以有意义的方式遍历它们。

无论如何,Aaron Bertrand sp_foreachdb是一段更好的代码,它不会跳过数据库等。