V SQL Server 2005 existuje způsob, jak najít uživatele, kteří buď neexistují na úrovni serveru (účet, který byl smazán na úrovni serveru, ale nebyl odstraněn z databází, než byl odstraněn), nebo účty, které nejsou propojeny. (účet mohl být smazán na úrovni serveru, ale ne na úrovni db, poté přečten, ale úroveň db nebyla nikdy vyčištěna).
Mám velmi chaotický server a bylo by úžasné, kdyby byl spuštěn dotaz k jejich nalezení.
následující skript z webu Brent Ozar Unlimited iteruje ve všech databázích a uvádí osiřelé uživatele podle databáze spolu s příkazem drop k jejich odstranění. Může to být hezčí/novější způsob, jak to zvládnout, ale zdá se, že v letech 2005-2012 funguje správně.
DECLARE @SQL nvarchar(2000)
DECLARE @name nvarchar(128)
DECLARE @database_id int
SET NOCOUNT ON;
IF NOT EXISTS
(SELECT name FROM tempdb.sys.tables WHERE name like '%#Orphan_users%')
BEGIN
CREATE TABLE #Orphan_users
(
database_name nvarchar(128) NOT NULL,
[user_name] nvarchar(128) NOT NULL,
drop_command_text nvarchar(200) NOT NULL
)
END
CREATE TABLE #databases
(
database_id int NOT NULL
, database_name nvarchar(128) NOT NULL
, processed bit NOT NULL
)
INSERT
#databases
( database_id
, database_name
, processed )
SELECT
database_id
, name
, 0
FROM
master.sys.databases
WHERE
name NOT IN
('master'
, 'tempdb'
, 'msdb'
, 'distribution'
, 'model')
WHILE (SELECT COUNT(processed) FROM #databases WHERE processed = 0) > 0
BEGIN
SELECT TOP 1
@name = database_name,
@database_id = database_id
FROM #databases
WHERE processed = 0
ORDER BY database_id
SELECT @SQL =
'USE [' + @name + '];
INSERT INTO #Orphan_users (database_name, user_name, drop_command_text)
SELECT
DB_NAME()
, u.name
, ' + ''''
+ 'USE [' + @name + ']; '
+ 'DROP USER ['
+ '''' + ' + u.name
+ ' + '''' + '] '
+ '''' + '
FROM
master..syslogins l
RIGHT JOIN
sysusers u
ON l.sid = u.sid
WHERE
l.sid IS NULL
AND issqlrole <> 1
AND isapprole <> 1
AND ( u.name <> ' + '''' + 'INFORMATION_SCHEMA' + ''''
+ ' AND u.name <> ' + '''' + 'guest' + ''''
+ ' AND u.name <> ' + '''' + 'dbo' + ''''
+ ' AND u.name <> ' + '''' + 'sys' + ''''
+ ' AND u.name <> ' + '''' + 'system_function_schema' + '''' + ')'
PRINT @SQL;
EXEC sys.sp_executesql @SQL
UPDATE
#databases
SET
processed = 1
WHERE
database_id = @database_id;
END
SELECT
database_name
, [user_name]
, drop_command_text
FROM
#Orphan_users
ORDER BY
[database_name]
, [user_name];
DROP TABLE #databases;
DROP TABLE #Orphan_users;
SET NOCOUNT OFF;
Chtěl jsem nejdřív DĚKUJI Mark za zaslání skriptu. Ušetřilo mi to spoustu času, když jsem to psal od nuly. Trochu jsem to upravil, protože jsem narazil na problém, kdy jsem obdržel chybu, která uvádí, že chyba „vedoucí databáze vlastní schéma v databázi a nelze ji zrušit“. Upravil jsem skript tak, aby generoval příkazy pro chybu SCHEMA a také pro chybu role, pokud byste ji měli také získat.
Doufám, že to někomu pomůže.
DECLARE @SQL nvarchar(2000)
DECLARE @name nvarchar(128)
DECLARE @database_id int
SET NOCOUNT ON;
IF NOT EXISTS
(SELECT name FROM tempdb.sys.tables WHERE name like '%#Orphan_users%')
BEGIN
CREATE TABLE #Orphan_users
(
database_name nvarchar(128) NOT NULL,
[user_name] nvarchar(128) NOT NULL,
drop_command_text nvarchar(200) NOT NULL,
drop_schema_text nvarchar(200) not null,
drop_role_text nvarchar(200) not null
)
END
CREATE TABLE #databases
(
database_id int NOT NULL
, database_name nvarchar(128) NOT NULL
, processed bit NOT NULL
)
INSERT
#databases
( database_id
, database_name
, processed )
SELECT
database_id
, name
, 0
FROM
master.sys.databases
WHERE
name NOT IN
('master'
, 'tempdb'
, 'msdb'
, 'distribution'
, 'model')
WHILE (SELECT COUNT(processed) FROM #databases WHERE processed = 0) > 0
BEGIN
SELECT TOP 1
@name = database_name,
@database_id = database_id
FROM #databases
WHERE processed = 0
ORDER BY database_id
SELECT @SQL =
'USE [' + @name + '];
INSERT INTO #Orphan_users (database_name, user_name, drop_command_text, Drop_schema_text, drop_role_text)
SELECT
DB_NAME()
, u.name
,
' + ''''
+ 'USE [' + @name + ']; '
+ 'DROP USER ['
+ '''' + ' + u.name
+ ' + '''' + '] '
+ '''' + '
,
' + '''' + 'USE [' + @name + ']; ' +
'ALTER AUTHORIZATION ON SCHEMA::['
+ '''' + ' + u.name
+ ' + '''' + '] TO [dbo]' + '''' + '
,
' + '''' + 'USE [' + @name + ']; ' +
'ALTER AUTHORIZATION ON Role::['
+ '''' + ' + u.name
+ ' + '''' + '] TO [dbo]' + '''' + '
FROM
master..syslogins l
RIGHT JOIN
sysusers u
ON l.sid = u.sid
WHERE
l.sid IS NULL
AND issqlrole <> 1
AND isapprole <> 1
AND ( u.name <> ' + '''' + 'INFORMATION_SCHEMA' + ''''
+ ' AND u.name <> ' + '''' + 'guest' + ''''
+ ' AND u.name <> ' + '''' + 'dbo' + ''''
+ ' AND u.name <> ' + '''' + 'sys' + ''''
+ ' AND u.name <> ' + '''' + 'system_function_schema' + '''' + ')'
PRINT @SQL;
EXEC sys.sp_executesql @SQL
UPDATE
#databases
SET
processed = 1
WHERE
database_id = @database_id;
END
SELECT
database_name
, [user_name]
, drop_command_text
, Drop_schema_text
, drop_role_text
FROM
#Orphan_users
ORDER BY
[database_name]
, [user_name];
DROP TABLE #databases;
DROP TABLE #Orphan_users;
SET NOCOUNT OFF;
Tento sp_change_users_login je od SQL 2008 odepisován, ale stále funguje dobře. Pokud předáte možnost „nahlásit“, zobrazí se seznam všech uživatelů, kteří nemají přidružené přihlašovací údaje.
EXEC sp_change_users_login 'report'
Pokud ji chcete spustit pro všechny své databáze, můžete to udělat takto.
EXEC sp_msforeachdb 'use [?]; PRINT ''?''; EXEC sp_change_users_login ''report'';'
Pokud se podíváte na BOL, najdete také možnosti pro opravu „osiřelých“ uživatelů.