0

我正在尝试执行以下 tsql

USE [master]
GO
CREATE LOGIN UserTest WITH Password = 'hi'
GO

sp_msforeachdb @command1= "CREATE USER [UserTest] FOR LOGIN [UserTest]"

重复出现以下错误(对于每个数据库):

Msg 15023, Level 16, State 1, Line 1
User, group, or role 'UserTest' already exists in the current database.

我对 sp_msforeachdb 的理解不正确吗?基本上,我正在尝试从现有登录名“UserTest”(用户映射)创建“UserTest”作为每个数据库上的用户,而不必单独为每个数据库编写代码。我是否以错误的方式处理这项任务?

有点像 TSQL 的初学者。只是想更彻底地理解语言

4

2 回答 2

2

请不要使用 sp_msforeachdb。它没有记录,不受支持,并且有一个我已经多次指出的错误,它实际上可以跳过数据库。我写了两个替代方案:

您应该做的是使用这些高级替代品之一,或者只是自己创建命令。您还应该检查用户是否已经存在,而不是仅仅在 SQL Server 上抛出一个潜在的错误。

DECLARE @sql NVARCHAR(MAX);
SET @sql = N'';

SELECT @sql = @sql + N'
IF NOT EXISTS (SELECT 1 FROM ' 
  + QUOTENAME(name) + '.sys.database_principals
  WHERE name = N''UserTest'')
    EXEC sys.sp_executesql N''USE ' + QUOTENAME(name) 
       + ';CREATE USER UserTest FOR LOGIN UserTest;'';'
FROM sys.databases
WHERE database_id > 4;

PRINT @sql; -- just to debug the first 8K

-- EXEC sys.sp_executesql @sql; 
-- uncomment the above line when you're happy with the output

您还可以在那里添加错误处理,例如

DECLARE @sql NVARCHAR(MAX);
SET @sql = N'';

SELECT @sql = @sql + N'
IF NOT EXISTS (SELECT 1 FROM ' 
  + QUOTENAME(name) + '.sys.database_principals
  WHERE name = N''UserTest'')
BEGIN
  BEGIN TRY
    EXEC sys.sp_executesql N''USE ' + QUOTENAME(name) 
    + ';CREATE USER UserTest FOR LOGIN UserTest;'';
  END TRY
  BEGIN CATCH
    PRINT ''Did not work for ' + name + ';''
  END CATCH
END'
FROM sys.databases
WHERE database_id > 4;

PRINT @sql;

-- EXEC sys.sp_executesql @sql; 
于 2013-03-25T20:56:10.380 回答
0

?值用作数据库名称的占位符,因此您的示例将是:

sp_msforeachdb @command1= 'USE [?]; CREATE USER [UserTest] FOR LOGIN [UserTest];'

使用未记录的存储过程时,请注意此处记录的陷阱。

于 2013-03-25T20:49:43.543 回答