2016-05-25 1 views
1

サーバー全体のデータベースアクセス許可を監査しようとしています。私は必要な出力を生成するクエリを持っていますが、すべてのデータベースに対して実行する必要があります。すべてのデータベースで大きなT-SQLクエリを実行します。

ほとんどのソリューションは、以下を使用して表示されます。

DECLARE @command varchar(1000) 
SELECT @command = 'USE ?; SQL QUERY HERE' 
EXEC sp_MSforeachdb @command 

しかしこれは私がDB自分でクエリを実行すると発生しないエラーと失敗します。私は変数に格納されているとは何かだと仮定し、それはまた、この形式を使用して失敗します。

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 

、私はこれを取得しますエラー(数回):

メッセージ102、レベル15、状態1、行 'THEN' 35
付近に正しくない構文。あなたはこれを実行しているサーバー内のすべてのデータベースを通過する必要はありません場合には

+0

可能性のある重複した[インスタンス上のすべてのデータベースで同じクエリを実行するには?](http://stackoverflow.com/questions/18462410/how-to-run-the-same-query-インスタンス上のデータベース全体) – dfundako

+0

投げられるエラーは何ですか? – Petaflop

+0

メッセージ102、レベル15、状態1、行35 'THEN'の近くの構文が正しくありません。 メッセージ102、レベル15、状態1、行35 'THEN'の近くの構文が正しくありません。/ SELECT msg 102、レベル15、状態1、行35 'THEN'に近い構文が正しくありません。 メッセージ102、レベル15、状態1、行35 'THEN'の近くの構文が正しくありません。 メッセージ102、レベル15、状態1、行35 'THEN'の近くの構文が正しくありません。 – 6502peeker

答えて

1

私はついにそれをカーソルを使用して動作させました(一部の人はそれが嫌いですが、動作します)。 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 
0
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。私は通常、SQLの一部として()DB_NAMEを使用するので、私はあなたのクエリが2000文字を超えているように見えます

1

特定の結果にリンクされているデシベルのフィードバックを得る -

以下
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 http://sqlblog.com/blogs/aaron_bertrand/archive/2010/02/08/bad-habits-to-kick-relying-on-undocumented-behavior.aspx 
*/ 
    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 
でsp_MSforEachDBを交換してみてください
関連する問題