运行 对所有数据库的大型 T-SQL 查询
Running a large T-SQL query on all databases
我正在尝试审核整个服务器上的数据库权限。我有一个生成我想要的输出的查询,但我需要针对所有数据库 运行 它。
大多数解决方案似乎使用以下内容:
DECLARE @command varchar(1000)
SELECT @command = 'USE ?; SQL QUERY HERE'
EXEC sp_MSforeachdb @command
然而,这失败并出现错误,当我 运行 我自己在数据库上查询时不会发生这种情况。我认为这与存储在变量中有关,但使用这种格式也失败了:
EXECUTE sp_MSForEachDB
'USE ?; SQL QUERY HERE'
我正在尝试 运行 的完整查询是:
SELECT
ServerName = @@SERVERNAME,
LoginName = AccessSummary.LoginName,
LoginType = CASE WHEN syslogins.isntuser = 1 THEN 'WINDOWS_LOGIN' WHEN syslogins.isntgroup = 1 THEN 'WINDOWS_GROUP' ELSE 'SQL_USER' END,
DatabaseName = DB_NAME(),
SelectAccess = MAX(AccessSummary.SelectAccess),
InsertAccess = MAX(AccessSummary.InsertAccess),
UpdateAccess = MAX(AccessSummary.UpdateAccess),
DeleteAccess = MAX(AccessSummary.DeleteAccess),
DBOAccess = MAX(AccessSummary.DBOAccess),
SysadminAccess = MAX(AccessSummary.SysadminAccess)
FROM
(
/* Get logins with permissions */
SELECT
LoginName = sysDatabasePrincipal.name,
SelectAccess = CASE WHEN permission_name = 'SELECT' THEN 1 ELSE 0 END,
InsertAccess = CASE WHEN permission_name = 'INSERT' THEN 1 ELSE 0 END,
UpdateAccess = CASE WHEN permission_name = 'UPDATE' THEN 1 ELSE 0 END,
DeleteAccess = CASE WHEN permission_name = 'DELETE' THEN 1 ELSE 0 END,
DBOAccess = 0,
SysadminAccess = 0
FROM sys.database_permissions AS sysDatabasePermission
INNER JOIN sys.database_principals AS sysDatabasePrincipal
ON sysDatabasePrincipal.principal_id = sysDatabasePermission.grantee_principal_id
INNER JOIN sys.server_principals AS sysServerPrincipal
ON sysServerPrincipal.sid = sysDatabasePrincipal.sid
WHERE sysDatabasePermission.class_desc = 'OBJECT_OR_COLUMN'
AND sysDatabasePrincipal.type_desc IN ('WINDOWS_LOGIN', 'WINDOWS_GROUP', 'SQL_USER')
AND sysServerPrincipal.is_disabled = 0
UNION ALL
/* Get group members with permissions */
SELECT
LoginName = sysDatabasePrincipalMember.name,
SelectAccess = CASE WHEN permission_name = 'SELECT' THEN 1 ELSE 0 END,
InsertAccess = CASE WHEN permission_name = 'INSERT' THEN 1 ELSE 0 END,
UpdateAccess = CASE WHEN permission_name = 'UPDATE' THEN 1 ELSE 0 END,
DeleteAccess = CASE WHEN permission_name = 'DELETE' THEN 1 ELSE 0 END,
DBOAccess = 0,
SysadminAccess = 0
FROM sys.database_permissions AS sysDatabasePermission
INNER JOIN sys.database_principals AS sysDatabasePrincipalRole
ON sysDatabasePrincipalRole.principal_id = sysDatabasePermission.grantee_principal_id
INNER JOIN sys.database_role_members AS sysDatabaseRoleMember
ON sysDatabaseRoleMember.role_principal_id = sysDatabasePrincipalRole.principal_id
INNER JOIN sys.database_principals AS sysDatabasePrincipalMember
ON sysDatabasePrincipalMember.principal_id = sysDatabaseRoleMember.member_principal_id
INNER JOIN sys.server_principals AS sysServerPrincipal
ON sysServerPrincipal.sid = sysDatabasePrincipalMember.sid
WHERE sysDatabasePermission.class_desc = 'OBJECT_OR_COLUMN'
AND sysDatabasePrincipalRole.type_desc = 'DATABASE_ROLE'
AND sysDatabasePrincipalRole.name <> 'public'
AND sysDatabasePrincipalMember.type_desc IN ('WINDOWS_LOGIN', 'WINDOWS_GROUP', 'SQL_USER')
AND sysServerPrincipal.is_disabled = 0
UNION ALL
/* Get users in db_owner, db_datareader and db_datawriter */
SELECT
LoginName = sysServerPrincipal.name,
SelectAccess = CASE WHEN sysDatabasePrincipalRole.name IN ('db_owner', 'db_datareader') THEN 1 ELSE 0 END,
InsertAccess = CASE WHEN sysDatabasePrincipalRole.name IN ('db_owner', 'db_datawriter') THEN 1 ELSE 0 END,
UpdateAccess = CASE WHEN sysDatabasePrincipalRole.name IN ('db_owner', 'db_datawriter') THEN 1 ELSE 0 END,
DeleteAccess = CASE WHEN sysDatabasePrincipalRole.name IN ('db_owner', 'db_datawriter') THEN 1 ELSE 0 END,
DBOAccess = CASE WHEN sysDatabasePrincipalRole.name = 'db_owner' THEN 1 ELSE 0 END,
SysadminAccess = 0
FROM sys.database_principals AS sysDatabasePrincipalRole
INNER JOIN sys.database_role_members AS sysDatabaseRoleMember
ON sysDatabaseRoleMember.role_principal_id = sysDatabasePrincipalRole.principal_id
INNER JOIN sys.database_principals AS sysDatabasePrincipalMember
ON sysDatabasePrincipalMember.principal_id = sysDatabaseRoleMember.member_principal_id
INNER JOIN sys.server_principals AS sysServerPrincipal
ON sysServerPrincipal.sid = sysDatabasePrincipalMember.sid
WHERE sysDatabasePrincipalRole.name IN ('db_owner', 'db_datareader', 'db_datawriter')
AND sysServerPrincipal.type_desc IN ('WINDOWS_LOGIN', 'WINDOWS_GROUP', 'SQL_LOGIN')
AND sysServerPrincipal.is_disabled = 0
UNION ALL
/* Get users in sysadmin */
SELECT
LoginName = sysServerPrincipalMember.name,
SelectAccess = 1,
InsertAccess = 1,
UpdateAccess = 1,
DeleteAccess = 1,
DBOAccess = 0,
SysadminAccess = 1
FROM sys.server_principals AS sysServerPrincipalRole
INNER JOIN sys.server_role_members AS sysServerRoleMember
ON sysServerRoleMember.role_principal_id = sysServerPrincipalRole.principal_id
INNER JOIN sys.server_principals AS sysServerPrincipalMember
ON sysServerPrincipalMember.principal_id = sysServerRoleMember.member_principal_id
WHERE sysServerPrincipalMember.type_desc IN ('WINDOWS_LOGIN', 'WINDOWS_GROUP', 'SQL_LOGIN')
AND sysServerPrincipalMember.is_disabled = 0
) AS AccessSummary
INNER JOIN MASTER.dbo.syslogins AS syslogins
ON syslogins.loginname = AccessSummary.LoginName
WHERE AccessSummary.LoginName NOT IN ('NT SERVICE\MSSQLSERVER', 'NT AUTHORITY\SYSTEM', 'NT SERVICE\SQLSERVERAGENT')
GROUP BY
AccessSummary.LoginName,
CASE WHEN syslogins.isntuser = 1 THEN 'WINDOWS_LOGIN' WHEN syslogins.isntgroup = 1 THEN 'WINDOWS_GROUP' ELSE 'SQL_USER' END
我收到此错误(多次):
Msg 102, Level 15, State 1, Line 35
Incorrect syntax near 'THEN'.
DECLARE @sqlCommand VARCHAR(8000)
SET @sqlCommand =
'
USE[?]
IF (db_name() like ''%Filter_DB_Name%'')
BEGIN
DECLARE @sql VARCHAR(1000)
SELECT @sql = ''<SQL Here>''
END
exec (@sql)'
EXEC sp_MSforeachdb @sqlCommand
如果您不想遍历 运行 服务器中的所有数据库,请使用 Filter_DB_Name。我通常使用 db_name() 作为 sql 的一部分,所以我得到链接到特定结果
的数据库的反馈
您的查询似乎超过了 2000 个字符 - 请尝试将 sp_MSforEachDB 替换为以下
CREATE Proc [Process].[ExecForEachDB] ( @cmd NVarchar(Max) )
As /*
Stored Procedure created by Chris Johnson
20th January 2016
The purpose of this stored procedure is to replace the undocumented procedure sp_MSforeachdb as this may be removed in future versions
of SQL Server. The stored procedure iterates through all user databases and executes the code passed to it.
Based off of https://sqlblog.org/2010/02/08/bad-habits-to-kick-relying-on-undocumented-behavior
*/
Begin
Set NoCount On;
--Declare variables
Declare @SqlScript NVarchar(Max)= ''
, @Database NVarchar(257)=''
, @ErrorMessage NVarchar(Max)='';
--Test validity, all scripts should contain a "?" to be used in place of a db name
If @cmd Not Like '%?%'
Begin
Set @ErrorMessage = Cast('' As NVarchar(max))
Set @ErrorMessage = @ErrorMessage+'ExecForEachDB failed, script does not contain the string "?" '
+ @cmd;
--If is included as permissions may not be available to create this table
If Object_Id('[History].[ExecForEachDBLogs]') Is Not Null
Begin
Insert [History].[ExecForEachDBErrorLogs]
( [Error] )
Values ( @ErrorMessage );
End;
If Object_Id('[History].[ExecForEachDBLogs]') Is Null
Begin
Raiserror ('** Warning - Errors are not being logged **',1,1); --if Errors are not being logged raise a low level error
End;
Raiserror (@ErrorMessage,13,1);
End;
If @cmd Like '%?%'
Begin
--Use Cursor to hold list of databases to execute against
Declare [DbNames] Cursor Local Forward_Only Static Read_Only
For
Select QuoteName([name])
From [sys].[databases]
Where [state] = 0 --online databases
And [is_read_only] = 0 --only databases that can be executed against
And [database_id] > 4 --only user databases
And has_dbaccess([name]) = 1 --only dbs current user has access to
Order By [name];
Open [DbNames];
Fetch Next From [DbNames] Into @Database; --Get first database to execute against
While @@fetch_status = 0 --when fetch is successful
Begin
Set @SqlScript = Cast('' As NVarchar(Max));
Set @SqlScript = @SqlScript
+ Replace(Replace(Replace(@cmd , '?' , @Database) ,
'[[' , '[') , ']]' , ']');--[[ & ]] caused by script including [?]
Begin Try
Exec(@SqlScript);
End Try
Begin Catch --if error happens against any db, raise a high level error advising the database and print the script
Set @ErrorMessage = Cast('' As NVarchar(max))
Set @ErrorMessage = @ErrorMessage + 'Script failed against database '
+ @Database;
Raiserror (@ErrorMessage,13,1);
Print @SqlScript;
End Catch;
Fetch Next From [DbNames] Into @Database;--Get next database to execute against
End;
Close [DbNames];
Deallocate [DbNames];
End;
End;
GO
我终于用游标让它工作了(有些人似乎讨厌它,但它确实有效)。您必须在 SQL 查询中使用两个单引号代替单引号。
DECLARE @db_name AS nvarchar(max)
DECLARE c_db_names CURSOR FOR
SELECT name
FROM sys.databases
WHERE name NOT IN('master', 'model', 'msdb', 'tempdb')
OPEN c_db_names
FETCH c_db_names INTO @db_name
WHILE @@Fetch_Status = 0
BEGIN
EXEC('
USE ' + @db_name + '
SELECT
ServerName = @@SERVERNAME,
DatabaseName = DB_NAME(),
LoginName = AccessSummary.LoginName,
LoginType = CASE WHEN syslogins.isntuser = 1 THEN ''WINDOWS_LOGIN'' WHEN syslogins.isntgroup = 1 THEN ''WINDOWS_GROUP'' ELSE ''SQL_USER'' END,
SelectAccess = MAX(AccessSummary.SelectAccess),
InsertAccess = MAX(AccessSummary.InsertAccess),
UpdateAccess = MAX(AccessSummary.UpdateAccess),
DeleteAccess = MAX(AccessSummary.DeleteAccess),
DBOAccess = MAX(AccessSummary.DBOAccess),
SysadminAccess = MAX(AccessSummary.SysadminAccess)
FROM
(
/* Get logins with permissions */
SELECT
LoginName = sysDatabasePrincipal.name,
SelectAccess = CASE WHEN permission_name = ''SELECT'' THEN 1 ELSE 0 END,
InsertAccess = CASE WHEN permission_name = ''INSERT'' THEN 1 ELSE 0 END,
UpdateAccess = CASE WHEN permission_name = ''UPDATE'' THEN 1 ELSE 0 END,
DeleteAccess = CASE WHEN permission_name = ''DELETE'' THEN 1 ELSE 0 END,
DBOAccess = 0,
SysadminAccess = 0
FROM sys.database_permissions AS sysDatabasePermission
INNER JOIN sys.database_principals AS sysDatabasePrincipal
ON sysDatabasePrincipal.principal_id = sysDatabasePermission.grantee_principal_id
INNER JOIN sys.server_principals AS sysServerPrincipal
ON sysServerPrincipal.sid = sysDatabasePrincipal.sid
WHERE sysDatabasePermission.class_desc = ''OBJECT_OR_COLUMN''
AND sysDatabasePrincipal.type_desc IN (''WINDOWS_LOGIN'', ''WINDOWS_GROUP'', ''SQL_USER'')
AND sysServerPrincipal.is_disabled = 0
UNION ALL
/* Get group members with permissions */
SELECT
LoginName = sysDatabasePrincipalMember.name,
SelectAccess = CASE WHEN permission_name = ''SELECT'' THEN 1 ELSE 0 END,
InsertAccess = CASE WHEN permission_name = ''INSERT'' THEN 1 ELSE 0 END,
UpdateAccess = CASE WHEN permission_name = ''UPDATE'' THEN 1 ELSE 0 END,
DeleteAccess = CASE WHEN permission_name = ''DELETE'' THEN 1 ELSE 0 END,
DBOAccess = 0,
SysadminAccess = 0
FROM sys.database_permissions AS sysDatabasePermission
INNER JOIN sys.database_principals AS sysDatabasePrincipalRole
ON sysDatabasePrincipalRole.principal_id = sysDatabasePermission.grantee_principal_id
INNER JOIN sys.database_role_members AS sysDatabaseRoleMember
ON sysDatabaseRoleMember.role_principal_id = sysDatabasePrincipalRole.principal_id
INNER JOIN sys.database_principals AS sysDatabasePrincipalMember
ON sysDatabasePrincipalMember.principal_id = sysDatabaseRoleMember.member_principal_id
INNER JOIN sys.server_principals AS sysServerPrincipal
ON sysServerPrincipal.sid = sysDatabasePrincipalMember.sid
WHERE sysDatabasePermission.class_desc = ''OBJECT_OR_COLUMN''
AND sysDatabasePrincipalRole.type_desc = ''DATABASE_ROLE''
AND sysDatabasePrincipalRole.name <> ''public''
AND sysDatabasePrincipalMember.type_desc IN (''WINDOWS_LOGIN'', ''WINDOWS_GROUP'', ''SQL_USER'')
AND sysServerPrincipal.is_disabled = 0
UNION ALL
/* Get users in db_owner, db_datareader and db_datawriter */
SELECT
LoginName = sysServerPrincipal.name,
SelectAccess = CASE WHEN sysDatabasePrincipalRole.name IN (''db_owner'', ''db_datareader'') THEN 1 ELSE 0 END,
InsertAccess = CASE WHEN sysDatabasePrincipalRole.name IN (''db_owner'', ''db_datawriter'') THEN 1 ELSE 0 END,
UpdateAccess = CASE WHEN sysDatabasePrincipalRole.name IN (''db_owner'', ''db_datawriter'') THEN 1 ELSE 0 END,
DeleteAccess = CASE WHEN sysDatabasePrincipalRole.name IN (''db_owner'', ''db_datawriter'') THEN 1 ELSE 0 END,
DBOAccess = CASE WHEN sysDatabasePrincipalRole.name = ''db_owner'' THEN 1 ELSE 0 END,
SysadminAccess = 0
FROM sys.database_principals AS sysDatabasePrincipalRole
INNER JOIN sys.database_role_members AS sysDatabaseRoleMember
ON sysDatabaseRoleMember.role_principal_id = sysDatabasePrincipalRole.principal_id
INNER JOIN sys.database_principals AS sysDatabasePrincipalMember
ON sysDatabasePrincipalMember.principal_id = sysDatabaseRoleMember.member_principal_id
INNER JOIN sys.server_principals AS sysServerPrincipal
ON sysServerPrincipal.sid = sysDatabasePrincipalMember.sid
WHERE sysDatabasePrincipalRole.name IN (''db_owner'', ''db_datareader'', ''db_datawriter'')
AND sysServerPrincipal.type_desc IN (''WINDOWS_LOGIN'', ''WINDOWS_GROUP'', ''SQL_LOGIN'')
AND sysServerPrincipal.is_disabled = 0
UNION ALL
/* Get users in sysadmin */
SELECT
LoginName = sysServerPrincipalMember.name,
SelectAccess = 1,
InsertAccess = 1,
UpdateAccess = 1,
DeleteAccess = 1,
DBOAccess = 0,
SysadminAccess = 1
FROM sys.server_principals AS sysServerPrincipalRole
INNER JOIN sys.server_role_members AS sysServerRoleMember
ON sysServerRoleMember.role_principal_id = sysServerPrincipalRole.principal_id
INNER JOIN sys.server_principals AS sysServerPrincipalMember
ON sysServerPrincipalMember.principal_id = sysServerRoleMember.member_principal_id
WHERE sysServerPrincipalMember.type_desc IN (''WINDOWS_LOGIN'', ''WINDOWS_GROUP'', ''SQL_LOGIN'')
AND sysServerPrincipalMember.is_disabled = 0
) AS AccessSummary
INNER JOIN MASTER.dbo.syslogins AS syslogins
ON syslogins.loginname = AccessSummary.LoginName
WHERE AccessSummary.LoginName NOT IN (''NT SERVICE\MSSQLSERVER'', ''NT AUTHORITY\SYSTEM'', ''NT SERVICE\SQLSERVERAGENT'')
GROUP BY
AccessSummary.LoginName,
CASE WHEN syslogins.isntuser = 1 THEN ''WINDOWS_LOGIN'' WHEN syslogins.isntgroup = 1 THEN ''WINDOWS_GROUP'' ELSE ''SQL_USER'' END')
FETCH c_db_names INTO @db_name
END
CLOSE c_db_names
DEALLOCATE c_db_names
我正在尝试审核整个服务器上的数据库权限。我有一个生成我想要的输出的查询,但我需要针对所有数据库 运行 它。
大多数解决方案似乎使用以下内容:
DECLARE @command varchar(1000)
SELECT @command = 'USE ?; SQL QUERY HERE'
EXEC sp_MSforeachdb @command
然而,这失败并出现错误,当我 运行 我自己在数据库上查询时不会发生这种情况。我认为这与存储在变量中有关,但使用这种格式也失败了:
EXECUTE sp_MSForEachDB
'USE ?; SQL QUERY HERE'
我正在尝试 运行 的完整查询是:
SELECT
ServerName = @@SERVERNAME,
LoginName = AccessSummary.LoginName,
LoginType = CASE WHEN syslogins.isntuser = 1 THEN 'WINDOWS_LOGIN' WHEN syslogins.isntgroup = 1 THEN 'WINDOWS_GROUP' ELSE 'SQL_USER' END,
DatabaseName = DB_NAME(),
SelectAccess = MAX(AccessSummary.SelectAccess),
InsertAccess = MAX(AccessSummary.InsertAccess),
UpdateAccess = MAX(AccessSummary.UpdateAccess),
DeleteAccess = MAX(AccessSummary.DeleteAccess),
DBOAccess = MAX(AccessSummary.DBOAccess),
SysadminAccess = MAX(AccessSummary.SysadminAccess)
FROM
(
/* Get logins with permissions */
SELECT
LoginName = sysDatabasePrincipal.name,
SelectAccess = CASE WHEN permission_name = 'SELECT' THEN 1 ELSE 0 END,
InsertAccess = CASE WHEN permission_name = 'INSERT' THEN 1 ELSE 0 END,
UpdateAccess = CASE WHEN permission_name = 'UPDATE' THEN 1 ELSE 0 END,
DeleteAccess = CASE WHEN permission_name = 'DELETE' THEN 1 ELSE 0 END,
DBOAccess = 0,
SysadminAccess = 0
FROM sys.database_permissions AS sysDatabasePermission
INNER JOIN sys.database_principals AS sysDatabasePrincipal
ON sysDatabasePrincipal.principal_id = sysDatabasePermission.grantee_principal_id
INNER JOIN sys.server_principals AS sysServerPrincipal
ON sysServerPrincipal.sid = sysDatabasePrincipal.sid
WHERE sysDatabasePermission.class_desc = 'OBJECT_OR_COLUMN'
AND sysDatabasePrincipal.type_desc IN ('WINDOWS_LOGIN', 'WINDOWS_GROUP', 'SQL_USER')
AND sysServerPrincipal.is_disabled = 0
UNION ALL
/* Get group members with permissions */
SELECT
LoginName = sysDatabasePrincipalMember.name,
SelectAccess = CASE WHEN permission_name = 'SELECT' THEN 1 ELSE 0 END,
InsertAccess = CASE WHEN permission_name = 'INSERT' THEN 1 ELSE 0 END,
UpdateAccess = CASE WHEN permission_name = 'UPDATE' THEN 1 ELSE 0 END,
DeleteAccess = CASE WHEN permission_name = 'DELETE' THEN 1 ELSE 0 END,
DBOAccess = 0,
SysadminAccess = 0
FROM sys.database_permissions AS sysDatabasePermission
INNER JOIN sys.database_principals AS sysDatabasePrincipalRole
ON sysDatabasePrincipalRole.principal_id = sysDatabasePermission.grantee_principal_id
INNER JOIN sys.database_role_members AS sysDatabaseRoleMember
ON sysDatabaseRoleMember.role_principal_id = sysDatabasePrincipalRole.principal_id
INNER JOIN sys.database_principals AS sysDatabasePrincipalMember
ON sysDatabasePrincipalMember.principal_id = sysDatabaseRoleMember.member_principal_id
INNER JOIN sys.server_principals AS sysServerPrincipal
ON sysServerPrincipal.sid = sysDatabasePrincipalMember.sid
WHERE sysDatabasePermission.class_desc = 'OBJECT_OR_COLUMN'
AND sysDatabasePrincipalRole.type_desc = 'DATABASE_ROLE'
AND sysDatabasePrincipalRole.name <> 'public'
AND sysDatabasePrincipalMember.type_desc IN ('WINDOWS_LOGIN', 'WINDOWS_GROUP', 'SQL_USER')
AND sysServerPrincipal.is_disabled = 0
UNION ALL
/* Get users in db_owner, db_datareader and db_datawriter */
SELECT
LoginName = sysServerPrincipal.name,
SelectAccess = CASE WHEN sysDatabasePrincipalRole.name IN ('db_owner', 'db_datareader') THEN 1 ELSE 0 END,
InsertAccess = CASE WHEN sysDatabasePrincipalRole.name IN ('db_owner', 'db_datawriter') THEN 1 ELSE 0 END,
UpdateAccess = CASE WHEN sysDatabasePrincipalRole.name IN ('db_owner', 'db_datawriter') THEN 1 ELSE 0 END,
DeleteAccess = CASE WHEN sysDatabasePrincipalRole.name IN ('db_owner', 'db_datawriter') THEN 1 ELSE 0 END,
DBOAccess = CASE WHEN sysDatabasePrincipalRole.name = 'db_owner' THEN 1 ELSE 0 END,
SysadminAccess = 0
FROM sys.database_principals AS sysDatabasePrincipalRole
INNER JOIN sys.database_role_members AS sysDatabaseRoleMember
ON sysDatabaseRoleMember.role_principal_id = sysDatabasePrincipalRole.principal_id
INNER JOIN sys.database_principals AS sysDatabasePrincipalMember
ON sysDatabasePrincipalMember.principal_id = sysDatabaseRoleMember.member_principal_id
INNER JOIN sys.server_principals AS sysServerPrincipal
ON sysServerPrincipal.sid = sysDatabasePrincipalMember.sid
WHERE sysDatabasePrincipalRole.name IN ('db_owner', 'db_datareader', 'db_datawriter')
AND sysServerPrincipal.type_desc IN ('WINDOWS_LOGIN', 'WINDOWS_GROUP', 'SQL_LOGIN')
AND sysServerPrincipal.is_disabled = 0
UNION ALL
/* Get users in sysadmin */
SELECT
LoginName = sysServerPrincipalMember.name,
SelectAccess = 1,
InsertAccess = 1,
UpdateAccess = 1,
DeleteAccess = 1,
DBOAccess = 0,
SysadminAccess = 1
FROM sys.server_principals AS sysServerPrincipalRole
INNER JOIN sys.server_role_members AS sysServerRoleMember
ON sysServerRoleMember.role_principal_id = sysServerPrincipalRole.principal_id
INNER JOIN sys.server_principals AS sysServerPrincipalMember
ON sysServerPrincipalMember.principal_id = sysServerRoleMember.member_principal_id
WHERE sysServerPrincipalMember.type_desc IN ('WINDOWS_LOGIN', 'WINDOWS_GROUP', 'SQL_LOGIN')
AND sysServerPrincipalMember.is_disabled = 0
) AS AccessSummary
INNER JOIN MASTER.dbo.syslogins AS syslogins
ON syslogins.loginname = AccessSummary.LoginName
WHERE AccessSummary.LoginName NOT IN ('NT SERVICE\MSSQLSERVER', 'NT AUTHORITY\SYSTEM', 'NT SERVICE\SQLSERVERAGENT')
GROUP BY
AccessSummary.LoginName,
CASE WHEN syslogins.isntuser = 1 THEN 'WINDOWS_LOGIN' WHEN syslogins.isntgroup = 1 THEN 'WINDOWS_GROUP' ELSE 'SQL_USER' END
我收到此错误(多次):
Msg 102, Level 15, State 1, Line 35
Incorrect syntax near 'THEN'.
DECLARE @sqlCommand VARCHAR(8000)
SET @sqlCommand =
'
USE[?]
IF (db_name() like ''%Filter_DB_Name%'')
BEGIN
DECLARE @sql VARCHAR(1000)
SELECT @sql = ''<SQL Here>''
END
exec (@sql)'
EXEC sp_MSforeachdb @sqlCommand
如果您不想遍历 运行 服务器中的所有数据库,请使用 Filter_DB_Name。我通常使用 db_name() 作为 sql 的一部分,所以我得到链接到特定结果
的数据库的反馈您的查询似乎超过了 2000 个字符 - 请尝试将 sp_MSforEachDB 替换为以下
CREATE Proc [Process].[ExecForEachDB] ( @cmd NVarchar(Max) )
As /*
Stored Procedure created by Chris Johnson
20th January 2016
The purpose of this stored procedure is to replace the undocumented procedure sp_MSforeachdb as this may be removed in future versions
of SQL Server. The stored procedure iterates through all user databases and executes the code passed to it.
Based off of https://sqlblog.org/2010/02/08/bad-habits-to-kick-relying-on-undocumented-behavior
*/
Begin
Set NoCount On;
--Declare variables
Declare @SqlScript NVarchar(Max)= ''
, @Database NVarchar(257)=''
, @ErrorMessage NVarchar(Max)='';
--Test validity, all scripts should contain a "?" to be used in place of a db name
If @cmd Not Like '%?%'
Begin
Set @ErrorMessage = Cast('' As NVarchar(max))
Set @ErrorMessage = @ErrorMessage+'ExecForEachDB failed, script does not contain the string "?" '
+ @cmd;
--If is included as permissions may not be available to create this table
If Object_Id('[History].[ExecForEachDBLogs]') Is Not Null
Begin
Insert [History].[ExecForEachDBErrorLogs]
( [Error] )
Values ( @ErrorMessage );
End;
If Object_Id('[History].[ExecForEachDBLogs]') Is Null
Begin
Raiserror ('** Warning - Errors are not being logged **',1,1); --if Errors are not being logged raise a low level error
End;
Raiserror (@ErrorMessage,13,1);
End;
If @cmd Like '%?%'
Begin
--Use Cursor to hold list of databases to execute against
Declare [DbNames] Cursor Local Forward_Only Static Read_Only
For
Select QuoteName([name])
From [sys].[databases]
Where [state] = 0 --online databases
And [is_read_only] = 0 --only databases that can be executed against
And [database_id] > 4 --only user databases
And has_dbaccess([name]) = 1 --only dbs current user has access to
Order By [name];
Open [DbNames];
Fetch Next From [DbNames] Into @Database; --Get first database to execute against
While @@fetch_status = 0 --when fetch is successful
Begin
Set @SqlScript = Cast('' As NVarchar(Max));
Set @SqlScript = @SqlScript
+ Replace(Replace(Replace(@cmd , '?' , @Database) ,
'[[' , '[') , ']]' , ']');--[[ & ]] caused by script including [?]
Begin Try
Exec(@SqlScript);
End Try
Begin Catch --if error happens against any db, raise a high level error advising the database and print the script
Set @ErrorMessage = Cast('' As NVarchar(max))
Set @ErrorMessage = @ErrorMessage + 'Script failed against database '
+ @Database;
Raiserror (@ErrorMessage,13,1);
Print @SqlScript;
End Catch;
Fetch Next From [DbNames] Into @Database;--Get next database to execute against
End;
Close [DbNames];
Deallocate [DbNames];
End;
End;
GO
我终于用游标让它工作了(有些人似乎讨厌它,但它确实有效)。您必须在 SQL 查询中使用两个单引号代替单引号。
DECLARE @db_name AS nvarchar(max)
DECLARE c_db_names CURSOR FOR
SELECT name
FROM sys.databases
WHERE name NOT IN('master', 'model', 'msdb', 'tempdb')
OPEN c_db_names
FETCH c_db_names INTO @db_name
WHILE @@Fetch_Status = 0
BEGIN
EXEC('
USE ' + @db_name + '
SELECT
ServerName = @@SERVERNAME,
DatabaseName = DB_NAME(),
LoginName = AccessSummary.LoginName,
LoginType = CASE WHEN syslogins.isntuser = 1 THEN ''WINDOWS_LOGIN'' WHEN syslogins.isntgroup = 1 THEN ''WINDOWS_GROUP'' ELSE ''SQL_USER'' END,
SelectAccess = MAX(AccessSummary.SelectAccess),
InsertAccess = MAX(AccessSummary.InsertAccess),
UpdateAccess = MAX(AccessSummary.UpdateAccess),
DeleteAccess = MAX(AccessSummary.DeleteAccess),
DBOAccess = MAX(AccessSummary.DBOAccess),
SysadminAccess = MAX(AccessSummary.SysadminAccess)
FROM
(
/* Get logins with permissions */
SELECT
LoginName = sysDatabasePrincipal.name,
SelectAccess = CASE WHEN permission_name = ''SELECT'' THEN 1 ELSE 0 END,
InsertAccess = CASE WHEN permission_name = ''INSERT'' THEN 1 ELSE 0 END,
UpdateAccess = CASE WHEN permission_name = ''UPDATE'' THEN 1 ELSE 0 END,
DeleteAccess = CASE WHEN permission_name = ''DELETE'' THEN 1 ELSE 0 END,
DBOAccess = 0,
SysadminAccess = 0
FROM sys.database_permissions AS sysDatabasePermission
INNER JOIN sys.database_principals AS sysDatabasePrincipal
ON sysDatabasePrincipal.principal_id = sysDatabasePermission.grantee_principal_id
INNER JOIN sys.server_principals AS sysServerPrincipal
ON sysServerPrincipal.sid = sysDatabasePrincipal.sid
WHERE sysDatabasePermission.class_desc = ''OBJECT_OR_COLUMN''
AND sysDatabasePrincipal.type_desc IN (''WINDOWS_LOGIN'', ''WINDOWS_GROUP'', ''SQL_USER'')
AND sysServerPrincipal.is_disabled = 0
UNION ALL
/* Get group members with permissions */
SELECT
LoginName = sysDatabasePrincipalMember.name,
SelectAccess = CASE WHEN permission_name = ''SELECT'' THEN 1 ELSE 0 END,
InsertAccess = CASE WHEN permission_name = ''INSERT'' THEN 1 ELSE 0 END,
UpdateAccess = CASE WHEN permission_name = ''UPDATE'' THEN 1 ELSE 0 END,
DeleteAccess = CASE WHEN permission_name = ''DELETE'' THEN 1 ELSE 0 END,
DBOAccess = 0,
SysadminAccess = 0
FROM sys.database_permissions AS sysDatabasePermission
INNER JOIN sys.database_principals AS sysDatabasePrincipalRole
ON sysDatabasePrincipalRole.principal_id = sysDatabasePermission.grantee_principal_id
INNER JOIN sys.database_role_members AS sysDatabaseRoleMember
ON sysDatabaseRoleMember.role_principal_id = sysDatabasePrincipalRole.principal_id
INNER JOIN sys.database_principals AS sysDatabasePrincipalMember
ON sysDatabasePrincipalMember.principal_id = sysDatabaseRoleMember.member_principal_id
INNER JOIN sys.server_principals AS sysServerPrincipal
ON sysServerPrincipal.sid = sysDatabasePrincipalMember.sid
WHERE sysDatabasePermission.class_desc = ''OBJECT_OR_COLUMN''
AND sysDatabasePrincipalRole.type_desc = ''DATABASE_ROLE''
AND sysDatabasePrincipalRole.name <> ''public''
AND sysDatabasePrincipalMember.type_desc IN (''WINDOWS_LOGIN'', ''WINDOWS_GROUP'', ''SQL_USER'')
AND sysServerPrincipal.is_disabled = 0
UNION ALL
/* Get users in db_owner, db_datareader and db_datawriter */
SELECT
LoginName = sysServerPrincipal.name,
SelectAccess = CASE WHEN sysDatabasePrincipalRole.name IN (''db_owner'', ''db_datareader'') THEN 1 ELSE 0 END,
InsertAccess = CASE WHEN sysDatabasePrincipalRole.name IN (''db_owner'', ''db_datawriter'') THEN 1 ELSE 0 END,
UpdateAccess = CASE WHEN sysDatabasePrincipalRole.name IN (''db_owner'', ''db_datawriter'') THEN 1 ELSE 0 END,
DeleteAccess = CASE WHEN sysDatabasePrincipalRole.name IN (''db_owner'', ''db_datawriter'') THEN 1 ELSE 0 END,
DBOAccess = CASE WHEN sysDatabasePrincipalRole.name = ''db_owner'' THEN 1 ELSE 0 END,
SysadminAccess = 0
FROM sys.database_principals AS sysDatabasePrincipalRole
INNER JOIN sys.database_role_members AS sysDatabaseRoleMember
ON sysDatabaseRoleMember.role_principal_id = sysDatabasePrincipalRole.principal_id
INNER JOIN sys.database_principals AS sysDatabasePrincipalMember
ON sysDatabasePrincipalMember.principal_id = sysDatabaseRoleMember.member_principal_id
INNER JOIN sys.server_principals AS sysServerPrincipal
ON sysServerPrincipal.sid = sysDatabasePrincipalMember.sid
WHERE sysDatabasePrincipalRole.name IN (''db_owner'', ''db_datareader'', ''db_datawriter'')
AND sysServerPrincipal.type_desc IN (''WINDOWS_LOGIN'', ''WINDOWS_GROUP'', ''SQL_LOGIN'')
AND sysServerPrincipal.is_disabled = 0
UNION ALL
/* Get users in sysadmin */
SELECT
LoginName = sysServerPrincipalMember.name,
SelectAccess = 1,
InsertAccess = 1,
UpdateAccess = 1,
DeleteAccess = 1,
DBOAccess = 0,
SysadminAccess = 1
FROM sys.server_principals AS sysServerPrincipalRole
INNER JOIN sys.server_role_members AS sysServerRoleMember
ON sysServerRoleMember.role_principal_id = sysServerPrincipalRole.principal_id
INNER JOIN sys.server_principals AS sysServerPrincipalMember
ON sysServerPrincipalMember.principal_id = sysServerRoleMember.member_principal_id
WHERE sysServerPrincipalMember.type_desc IN (''WINDOWS_LOGIN'', ''WINDOWS_GROUP'', ''SQL_LOGIN'')
AND sysServerPrincipalMember.is_disabled = 0
) AS AccessSummary
INNER JOIN MASTER.dbo.syslogins AS syslogins
ON syslogins.loginname = AccessSummary.LoginName
WHERE AccessSummary.LoginName NOT IN (''NT SERVICE\MSSQLSERVER'', ''NT AUTHORITY\SYSTEM'', ''NT SERVICE\SQLSERVERAGENT'')
GROUP BY
AccessSummary.LoginName,
CASE WHEN syslogins.isntuser = 1 THEN ''WINDOWS_LOGIN'' WHEN syslogins.isntgroup = 1 THEN ''WINDOWS_GROUP'' ELSE ''SQL_USER'' END')
FETCH c_db_names INTO @db_name
END
CLOSE c_db_names
DEALLOCATE c_db_names