2013-10-03 3 views
0

아래 코드를 사용하여 잘된 데이터베이스에 대한 고아 사용자 목록을 제공하고 있습니다. 이제는 데이터베이스 목록을 반복하여 결과를 단일 테이블로 반환하는 무언가에이 작업을 구현하려고합니다. 여기 SQL - 데이터베이스 목록을 반복하여 고아가 된 사용자에 대한 단일 결과를 반환합니다.

내가 분리 된 사용자를 얻기 위해 사용하고있는 코드입니다 :

select DB_NAME() AS [Current Database], u.uid, u.name, u.sid, rm.role_principal_id as 'Role ID', dp1.name as 'Role' 
from sys.sysusers u 
left join sys.syslogins l on UPPER(u.sid) = UPPER(l.sid) 
inner join sys.database_role_members rm on rm.member_principal_id = u.uid 
left join sys.database_principals dp on dp.principal_id = rm.member_principal_id 
left join sys.database_principals dp1 on dp1.principal_id = rm.role_principal_id 
where u.uid > 4 and u.issqlrole = 0 
--and issqluser = 1 --commented out to include orphaned windows logins 
and l.name is null 
order by 1 

내가 아래 사용하여 데이터베이스의 목록을 얻을 수 있지만 차례로 각각의 데이터베이스를 통해 이동합니다 위의와 결합하려는.

SELECT name FROM sys.databases 
WHERE database_id > 4 

이 부분에 대한 도움이나 조언이 있으면 감사하겠습니다.

답변

0

당신은 각 데이터베이스에 대해 SQL 문 집합을 실행하는 시스템 저장 프로 시저 sp_msforeachdb를 사용할 수 있습니다. 이 프로 시저를 실행할 때마다 별도의 결과 집합이 반환되므로 임시 테이블을 사용하여 모든 결과를 단일 테이블로 수집합니다. 그런 다음이 단일 테이블을 일반 SQL을 사용하여 최종 결과를 필터링하고 정렬 할 수 있습니다.

IF OBJECT_ID('tempdb..#Orphans') IS NOT NULL 
    DROP TABLE #Orphans 

CREATE TABLE #Orphans 
(
    [Current Database] SYSNAME, 
    [uid]    SMALLINT, 
    [name]    SYSNAME, 
    [sid]    VARBINARY(85), 
    [Role ID]   SMALLINT, 
    [Role]    SYSNAME 
) 

INSERT #Orphans 
EXEC sp_msforeachdb 'use [?]; 
    select DB_NAME() AS [Current Database] 
     , u.uid, u.name 
     , u.sid 
     , rm.role_principal_id as [Role ID] 
     , dp1.name as [Role] 
     from sys.sysusers u 
      left join sys.syslogins l 
       on UPPER(u.sid) = UPPER(l.sid) 
       inner join sys.database_role_members rm 
        on rm.member_principal_id = u.uid 
        left join sys.database_principals dp 
         on dp.principal_id = rm.member_principal_id 
         left join sys.database_principals dp1 
          on dp1.principal_id = rm.role_principal_id 
    where u.uid > 4 and u.issqlrole = 0 
    --and issqluser = 1 --commented out to include orphaned windows logins 
     and l.name is null 
    order by 1' 

SELECT * FROM #Orphans 

몇 가지주의해야 할 점은 "?" 문자는 SQL 템플리트에서 새 템플리트에서 템플리트가 실행될 때마다 데이터베이스 이름으로 채워집니다. 또한 작은 따옴표 대신 "["문자를 사용하도록 열 별칭을 변경했습니다.

+0

이것은 정확히 내가 필요한 것입니다. 많은 감사합니다! – Matt

0

:-)

덕분에 나는 다른 데이터베이스에 쿼리를 실행을 알고있는 유일한 방법은 데이터베이스 이름과 각 반복에서 (원하는 데이터베이스 이름) 동적 쿼리를 실행을 반복하는 커서를 사용하는 것입니다.

동적 쿼리에서 테이블 변수를 사용하는 데 어려움을 피하기 위해 결과를 저장할 로컬 임시 테이블 (단일 # 접두어)을 사용했습니다.

이 작업을 수행하려면 각각 schema.table의 접두어에 각 반복의 데이터베이스 이름으로 대체되는 자리 표시자를 붙여야했습니다. 이렇게하면 각 테이블은 db.schema.table으로 정규화됩니다.

마찬가지로 EXEC을 사용하면 SQL 삽입에 취약하다는 것을 알아 두십시오.

나는 이것이 당신을 도움이되기를 바랍니다 :

CREATE TABLE #results (
    currdb sysname, 
    uid int, 
    uname sysname, 
    usid int, 
    rpid int, 
    rname sysname) 

DECLARE @sqltemplate VARCHAR(4000), @sql VARCHAR(4000) 
SET @sqltemplate = 'SELECT 
    ''[@db]'', u.uid, u.name, u.sid, rm.role_principal_id, dp1.name 
    FROM [@db].sys.sysusers u 
     LEFT JOIN [@db].sys.syslogins l ON UPPER(u.sid) = UPPER(l.sid) 
     INNER JOIN [@db].sys.database_role_members rm 
      ON rm.member_principal_id = u.uid 
     LEFT JOIN [@db].sys.database_principals dp 
      ON dp.principal_id = rm.member_principal_id 
     LEFT JOIN [@db].sys.database_principals dp1 
      ON dp1.principal_id = rm.role_principal_id 
    WHERE u.uid > 4 AND u.issqlrole = 0 AND l.name IS NULL 
    ORDER BY 1' 

DECLARE @dbname sysname 

DECLARE dbnames CURSOR FOR 
    SELECT name FROM sys.databases WHERE database_id > 4 

OPEN dbnames 

FETCH NEXT FROM dbnames INTO @dbname 

WHILE @@FETCH_STATUS = 0 
BEGIN 
    SET @sql = REPLACE(@sqltemplate, '@db', @dbname) 
    INSERT #results 
    EXEC (@sql) 
    FETCH NEXT FROM dbnames INTO @dbname 
END 
CLOSE dbnames 
DEALLOCATE dbnames 

SELECT * FROM #results 
DROP TABLE #results