我之前使用过此SP。现在,我正在尝试使用下面的代码允许用户使用相同字母开头的50个奇数数据库。看起来它在代码中不喜欢“GO”。这是为什么 ?什么是工作?
感谢您的时间.. :)
RM
exec sp_MSForEachDB
'
IF ''?'' LIKE ''MYDBNames%''
BEGIN
Use [?]
Go
CREATE USER [MYDOMAIN\Analysts] FOR LOGIN [MYDOMAIN\Analysts]
GO
EXEC sp_addrolemember N''db_owner'', N''MYDOMAIN\Analysts''
GO
END
答案 0 :(得分:4)
我昨天在另一个问题中解释了这一点(here)。这个本质是这样的:GO
不是SQL语句,它是一个SSMS / SQLCMD命令,用于分离批处理(一起编译的SQL语句组)。所以你不能在存储过程或动态SQL之类的东西中使用它。此外,很少有语句上下文可以跨越GO
边界(事务和会话级临时表是关于它的。)
但是,因为存储过程和动态SQL都建立了自己独立的批处理/执行上下文,所以您可以使用它们来解决GO
的正常需求,如下所示:
exec sp_MSForEachDB
'
IF ''?'' LIKE ''MYDBNames%''
BEGIN
Use [?]
EXEC(''
CREATE USER [MYDOMAIN\Analysts] FOR LOGIN [MYDOMAIN\Analysts]
'')
EXEC('' EXEC sp_addrolemember N''''db_owner'''', N''''MYDOMAIN\Analysts'''' '')
END
'
答案 1 :(得分:2)
单词GO
是批处理分隔符,不是SQL关键字。在SSMS中,您可以转到选项并将其更改为任何内容 - 例如COME
。
试试这个:
exec sp_MSForEachDB
'
IF ''?'' LIKE ''MYDBNames%''
BEGIN;
Use [?];
CREATE USER [MYDOMAIN\Analysts] FOR LOGIN [MYDOMAIN\Analysts];
EXEC sp_addrolemember N''db_owner'', N''MYDOMAIN\Analysts'';
END;'
答案 2 :(得分:1)
GO
,这不是必需的(它甚至不是T-SQL;它只是Management Studio的批处理分隔符)。sp_MSForEachDB
。哦,问题(如果你想要证明,请参阅here,here和here)。以下是不使用任何存储过程执行此操作的代码:
DECLARE @sql NVARCHAR(MAX) = N'';
SELECT @sql += N'USE ' + QUOTENAME(name) + ';
CREATE USER [MYDOMAIN\Analysts] FOR LOGIN [MYDOMAIN\Analysts];
EXEC sp_addrolemember N''db_owner'', N''MYDOMAIN\Analysts'';
'
FROM sys.databases
WHERE state = 0 -- online
AND name LIKE N'MyDBName%';
PRINT @sql;
-- EXEC sp_executesql @sql;
答案 3 :(得分:0)
为什么不使用光标?
他们非常适合这样的管理任务。只要记录集很小,它们就能表现良好。
下面的代码为每个使用;的数据库创建一个SQL语句。结合多个任务。
与上述代码不同,它会在创建新用户之前删除所有现有用户。避免可能的问题。
然后它执行代码。如果需要,您甚至可以将这些adhoc请求记录到内部表中并添加错误检查。
祝你好运。--
-- EXEC same statements against several like databases
--
-- Declare local variables
DECLARE @STMT NVARCHAR(4000);
-- Allocate cursor, return table names
DECLARE MYTRG CURSOR FAST_FORWARD FOR
SELECT
' use [' + ltrim(rtrim(d.name)) + ']; ' +
' IF EXISTS (SELECT * FROM sys.database_principals WHERE name = N''[MYDOMAIN\Analysts]'') DROP USER [MYDOMAIN\Analysts]; ' +
' CREATE USER [MYDOMAIN\Analysts] FOR LOGIN [MYDOMAIN\Analysts] WITH DEFAULT_SCHEMA=[DBO]; ' +
' sp_addrolemember N''db_owner'', N''MYDOMAIN\Analysts''; ' as STMT
FROM master.dbo.sysdatabases d
WHERE d.name like 'MYDBNames%'
ORDER BY d.name;
-- Open cursor
OPEN MYTRG;
-- Get the first row
FETCH NEXT FROM MYTRG INTO @STMT;
-- While there is data
WHILE (@@FETCH_STATUS = 0)
BEGIN
-- Show detail database info
EXEC sp_executesql @STMT;
-- Get the first row
FETCH NEXT FROM MYTRG INTO @STMT;
END;
-- Close the cursor
CLOSE MYTRG;
-- Release the cursor
DEALLOCATE MYTRG;
答案 4 :(得分:0)
与@ RBarryYoung的答案一样,当命令带有必须是“批处理中的第一个”的要求时,可以使用嵌入式exec()来避免需要“go”。我不认为问题的例子需要“去”,但标题本身可能会引导人们到这里来。
这是一个基本的SP来包装这个支持的DDL语句,如“create proc”,并提供一些错误消息。我可能是第五个做这件事的人,这个人不是最终的全部。
Blessing / Curse:调用Common.ufn_UsvToNVarcharKeyTable(),您可能需要在自己的CSV分割器中进行修补或删除:
alter proc [Common].[usp_ForEachDatabase]
@pSql nvarchar(max),
@pDatabaseNameLikeOpt nvarchar(300) = null, -- Optional pattern to match with like
@pDatabaseNameCsvOpt nvarchar(max) = null, -- Optional list of DBs
@pJustPrintDbNames bit = 0, -- Don't exec, just print database names
@pDebug bit = 1 -- may add additional print statements
as
/*-----------------------------------------------------------------------------------------------------------------
Purpose: Execute SQL on each database. Replacement for the standard sp_MSForEachDB which has a size character
limit and requires an exec() within for DDL commands which must be the first in a batch.
Sources: Ideas from http://www.experts-exchange.com/Database/MS-SQL-Server/SQL-Server-2005/Q_26337388.html
http://stackoverflow.com/questions/20125430
http://stackoverflow.com/questions/1819095/
Modified By Description
---------- ---------- -----------------------------------------------------------------------------------
2014.10.14 crokusek Initial version. Pieces from internet.
--------------------------------------------------------------------------------------------------------------*/
begin try
declare databaseCursor cursor local forward_only static for
select IsNull(sd.Name, ud.Name) as Name,
--
-- If a list was specified, flag when a name was not found
--
convert(bit, iif(sd.Name is null, 1, 0)) as IsNotFound
from
(
select Name from sys.databases
where Name not in ('master', 'tempdb', 'model', 'msdb')
and is_distributor = 0 -- http://stackoverflow.com/questions/1819095/
) sd
full outer join ( select Value as Name from Common.ufn_UsvToNVarcharKeyTable(@pDatabaseNameCsvOpt, ',' ) ) ud
on ud.Name = sd.Name
where (@pDatabaseNameLikeOpt is null or IsNull(sd.Name, ud.Name) like @pDatabaseNameLikeOpt)
and (@pDatabaseNameCsvOpt is null or ud.Name is not null)
order by IsNull(sd.Name, ud.Name);
declare
@matchingDatabaseNames nvarchar(max),
@databaseName nvarchar(300),
@isNotFound bit,
@errorCount int = 0,
@successCount int = 0,
--
-- Use an embedded exec() to place the user command(s) in a separate context to avoid errors like:
-- CREATE/ALTER PROCEDURE must be the first statement in a query batch.
--
@sqlExec nvarchar(max) = N'exec (''' + replace(@pSql, '''', '''''') + ''')';
open databaseCursor
fetch next from databaseCursor into @databaseName, @isNotFound;
while @@fetch_status = 0
begin
if (@isNotFound = 1)
begin
print 'Error: Database ' + @databaseName + ' was not found.';
set @errorCount += 1;
end
else
begin
set @matchingDatabaseNames = coalesce(@matchingDatabaseNames + ',', '') + @databaseName; -- Create Csv
print 'Database: ' + @databaseName;
if (@pJustPrintDbNames = 0)
begin
declare
@execSql nvarchar(max) = 'use ' + @databaseName + ';' + char(10) + @sqlExec;
begin try
exec (@execSql)
set @successCount += 1;
end try
begin catch
select @databaseName as [Database],
error_number() as ErrorNumber,
error_severity() as ErrorSeverity,
error_state() as ErrorState,
error_procedure() as ErrorProcedure,
error_line() as ErrorLine,
error_message() as ErrorMessage;
set @errorCount += 1;
end catch
end
end
fetch next from databaseCursor into @databaseName, @isNotFound;
end
if (@pJustPrintDbNames = 1)
print @matchingDatabaseNames; -- this can then be used as input
else
print 'Completed with ' + convert(varchar(30), @errorCount) + ' Errors ' +
'and ' + convert(varchar(30), @successCount) + ' Successes.';
end try
begin catch
if (xact_state() = -1)
rollback;
-- Log / Rethrow
end catch
go
用法:
declare
@sql nvarchar(max) = N'
create proc usp_ReplaceEachSingleQuoteWithTwoSingleQuotesInTheDefinition
...';
exec [Common].[usp_ForEachDatabase]
@pSql = @sql,
@pDatabaseNameLikeOpt = null,
@pDatabaseNameCsvOpt = null,
@pJustPrintDbNames = 0,
@pDebug = 1;