2016-05-25 3 views
1

Я пытаюсь проверить разрешения базы данных на весь сервер. У меня есть запрос, который производит вывод, который я хочу, но мне нужно запустить его во всех базах данных.Запуск большого запроса T-SQL во всех базах данных

Большинство решений, похоже, используют следующее:

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
Неправильный синтаксис около 'THEN'.

+0

Возможный дубликат [Как запустить тот же запрос на всех базах данных на экземпляре?] (Http://stackoverflow.com/questions/18462410/how-to-run-the-same-query- on-all-the-databases-on-the-instance) – dfundako

+0

Какова ошибка при запуске? – Petaflop

+0

Msg 102, Level 15, State 1, Line 35 Неверный синтаксис рядом с «THEN». Msg 102, Level 15, State 1, Line 35 Неверный синтаксис рядом с «THEN». Это выдвигает на первый план: /* Получить членов группы с правами доступа */ ВЫБРАТЬ Msg 102, Level 15, State 1, Line 35 Неправильный синтаксис около 'THEN'. Msg 102, Level 15, State 1, Line 35 Неверный синтаксис рядом с «THEN». Msg 102, Level 15, State 1, Line 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 в случае, если вы не хотите, чтобы пройти через все базы данных на сервере, где это работает. Я обычно использую db_name() как часть SQL, так что я получаю обратную связь БД, связанную с конкретным результатом

1

Похоже, ваш запрос больше 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 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 

 Смежные вопросы

  • Нет связанных вопросов^_^