SQL Server Management Studioでデータベースのバックアップと復元を使用して、データベース(SQL Express 2012)を開発マシンからサーバーに、またはその逆にときどき移動します。
これを行うと、ターゲットマシン上のアプリケーションは、使用しているユーザー「george」をデータベースユーザー(SQL Server Management Studioのデータベース、セキュリティ、ユーザー)から削除して、次のように再度追加するまで、データベースにアクセスできません。セキュリティ、ログイン、george/properties、ユーザーマッピングの下の所有者。
これを行うより良い方法はありますか?少し複雑なようです。
これが logins と sers の違いと、それらの相互関係です。
復元時にSQL認証ログインとデータベースユーザーで一般的に発生するのは、SIDSが同期していないため、関係が壊れることです。そのログインを使用してデータベースに接続する前に、この関係を修復する必要があります。SQLServerの観点から、これらのプリンシパルは接続されなくなったためです。これは次のSQLで修正できます。
ALTER USER [foo] WITH LOGIN=[foo]
データベースのコンテキストで次のクエリを使用して、孤立ファイルを確認できます。
select
dp.name [user_name]
,dp.type_desc [user_type]
,isnull(sp.name,'Orhphaned!') [login_name]
,sp.type_desc [login_type]
from
sys.database_principals dp
left join sys.server_principals sp on (dp.sid = sp.sid)
where
dp.type in ('S','U','G')
and dp.principal_id >4
order by sp.name
データベースを 包含データベース に変更することを検討できます。包含データベースユーザーは、ログインを通じてインスタンスレベルではなく、データベースによって認証されます。これにより、データベースを別のインスタンスに簡単に移動できます。
そうでない場合は、このサイトで提供されているsp_help_revloginスクリプトを使用してログイン情報をバックアップできます Microsoft support KB 。そして、新しいインスタンスで出力スクリプトを実行します。
ここ は私のために働いた解決策です。それがすることは:
EXEC sp_change_users_login 'REPORT'
EXEC sp_change_users_login 'UPDATE_ONE','<userName>','<userName>'
以下のスクリプトを使用して、ユーザーアカウントとログインを移行/作成します。データベースを復元したサーバーからそれを実行し、元のサーバー名をパラメーターとしてプロシージャーに指定します。
他の場所から入手したので、この手順は信用していませんが、問題なく機能します。
USE [master]
GO
/****** Object: StoredProcedure [dbo].[stp_Admin_ReplicateUserLogins] Script Date: 10/29/2015 08:22:43 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER Procedure [dbo].[stp_Admin_ReplicateUserLogins] --'OriginalSourceDatabase', 1
@PartnerServer sysname,
@Debug bit = 0 -- 0 = Create Users, 1 = Display SQL command but doesn't execute query.
As
Declare @MaxID int,
@CurrID int,
@SQL nvarchar(max),
@LoginName sysname,
@IsDisabled int,
@Type char(1),
@SID varbinary(85),
@SIDString nvarchar(100),
@PasswordHash varbinary(256),
@PasswordHashString nvarchar(300),
@RoleName sysname,
@Machine sysname,
@PermState nvarchar(60),
@PermName sysname,
@Class tinyint,
@MajorID int,
@ErrNumber int,
@ErrSeverity int,
@ErrState int,
@ErrProcedure sysname,
@ErrLine int,
@ErrMsg nvarchar(2048)
Declare @Logins Table (LoginID int identity(1, 1) not null primary key,
[Name] sysname not null,
[SID] varbinary(85) not null,
IsDisabled int not null,
[Type] char(1) not null,
PasswordHash varbinary(256) null)
Declare @Roles Table (RoleID int identity(1, 1) not null primary key,
RoleName sysname not null,
LoginName sysname not null)
Declare @Perms Table (PermID int identity(1, 1) not null primary key,
LoginName sysname not null,
PermState nvarchar(60) not null,
PermName sysname not null,
Class tinyint not null,
ClassDesc nvarchar(60) not null,
MajorID int not null,
SubLoginName sysname null,
SubEndPointName sysname null)
Set NoCount On;
If CharIndex('\', @PartnerServer) > 0
Begin
Set @Machine = LEFT(@PartnerServer, CharIndex('\', @PartnerServer) - 1);
End
Else
Begin
Set @Machine = @PartnerServer;
End
-- Get all Windows logins from principal server
Set @SQL = 'Select P.name, P.sid, P.is_disabled, P.type, L.password_hash' + CHAR(10) +
'From ' + QUOTENAME(@PartnerServer) + '.master.sys.server_principals P' + CHAR(10) +
'Left Join ' + QUOTENAME(@PartnerServer) + '.master.sys.sql_logins L On L.principal_id = P.principal_id' + CHAR(10) +
'Where P.type In (''U'', ''G'', ''S'')' + CHAR(10) +
'And P.name <> ''sa''' + CHAR(10) +
'And P.name Not Like ''##%''' + CHAR(10) +
'and P.Name Not like ''NT SERVICE%''' + CHAR(10) +
'And CharIndex(''' + @Machine + '\'', P.name) = 0;';
Insert Into @Logins (Name, SID, IsDisabled, Type, PasswordHash)
Exec sp_executesql @SQL;
-- Get all roles from principal server
Set @SQL = 'Select RoleP.name, LoginP.name' + CHAR(10) +
'From ' + QUOTENAME(@PartnerServer) + '.master.sys.server_role_members RM' + CHAR(10) +
'Inner Join ' + QUOTENAME(@PartnerServer) + '.master.sys.server_principals RoleP' +
CHAR(10) + char(9) + 'On RoleP.principal_id = RM.role_principal_id' + CHAR(10) +
'Inner Join ' + QUOTENAME(@PartnerServer) + '.master.sys.server_principals LoginP' +
CHAR(10) + char(9) + 'On LoginP.principal_id = RM.member_principal_id' + CHAR(10) +
'Where LoginP.type In (''U'', ''G'', ''S'')' + CHAR(10) +
'And LoginP.name <> ''sa''' + CHAR(10) +
'And LoginP.name Not Like ''##%''' + CHAR(10) +
'And LoginP.name Not Like ''NT SERVICE%''' + CHAR(10) +
'And RoleP.type = ''R''' + CHAR(10) +
'And CharIndex(''' + @Machine + '\'', LoginP.name) = 0;';
Insert Into @Roles (RoleName, LoginName)
Exec sp_executesql @SQL;
-- Get all explicitly granted permissions
Set @SQL = 'Select P.name Collate database_default,' + CHAR(10) +
' SP.state_desc, SP.permission_name, SP.class, SP.class_desc, SP.major_id,' + CHAR(10) +
' SubP.name Collate database_default,' + CHAR(10) +
' SubEP.name Collate database_default' + CHAR(10) +
'From ' + QUOTENAME(@PartnerServer) + '.master.sys.server_principals P' + CHAR(10) +
'Inner Join ' + QUOTENAME(@PartnerServer) + '.master.sys.server_permissions SP' + CHAR(10) +
CHAR(9) + 'On SP.grantee_principal_id = P.principal_id' + CHAR(10) +
'Left Join ' + QUOTENAME(@PartnerServer) + '.master.sys.server_principals SubP' + CHAR(10) +
CHAR(9) + 'On SubP.principal_id = SP.major_id And SP.class = 101' + CHAR(10) +
'Left Join ' + QUOTENAME(@PartnerServer) + '.master.sys.endpoints SubEP' + CHAR(10) +
CHAR(9) + 'On SubEP.endpoint_id = SP.major_id And SP.class = 105' + CHAR(10) +
'Where P.type In (''U'', ''G'', ''S'')' + CHAR(10) +
'And P.name <> ''sa''' + CHAR(10) +
'And P.name Not Like ''##%''' + CHAR(10) +
'And P.name Not Like ''NT SERVICE%''' + CHAR(10) +
'And CharIndex(''' + @Machine + '\'', P.name) = 0;'
Insert Into @Perms (LoginName, PermState, PermName, Class, ClassDesc, MajorID, SubLoginName, SubEndPointName)
Exec sp_executesql @SQL;
Select @MaxID = Max(LoginID), @CurrID = 1
From @Logins;
While @CurrID <= @MaxID
Begin
Select @LoginName = Name,
@IsDisabled = IsDisabled,
@Type = [Type],
@SID = [SID],
@PasswordHash = PasswordHash
From @Logins
Where LoginID = @CurrID;
If Not Exists (Select 1 From sys.server_principals
Where name = @LoginName)
Begin
Set @SQL = 'Create Login ' + quotename(@LoginName)
If @Type In ('U', 'G')
Begin
Set @SQL = @SQL + ' From Windows;'
End
Else
Begin
Set @PasswordHashString = '0x' +
Cast('' As XML).value('xs:hexBinary(sql:variable("@PasswordHash"))', 'nvarchar(300)');
Set @SQL = @SQL + ' With Password = ' + @PasswordHashString + ' HASHED, ';
Set @SIDString = '0x' +
Cast('' As XML).value('xs:hexBinary(sql:variable("@SID"))', 'nvarchar(100)');
Set @SQL = @SQL + 'SID = ' + @SIDString + ';';
End
If @Debug = 0
Begin
Begin Try
Exec sp_executesql @SQL;
End Try
Begin Catch
Set @ErrNumber = ERROR_NUMBER();
Set @ErrSeverity = ERROR_SEVERITY();
Set @ErrState = ERROR_STATE();
Set @ErrProcedure = ERROR_PROCEDURE();
Set @ErrLine = ERROR_LINE();
Set @ErrMsg = ERROR_MESSAGE();
RaisError(@ErrMsg, 1, 1);
End Catch
End
Else
Begin
Print @SQL;
End
If @IsDisabled = 1
Begin
Set @SQL = 'Alter Login ' + quotename(@LoginName) + ' Disable;'
If @Debug = 0
Begin
Begin Try
Exec sp_executesql @SQL;
End Try
Begin Catch
Set @ErrNumber = ERROR_NUMBER();
Set @ErrSeverity = ERROR_SEVERITY();
Set @ErrState = ERROR_STATE();
Set @ErrProcedure = ERROR_PROCEDURE();
Set @ErrLine = ERROR_LINE();
Set @ErrMsg = ERROR_MESSAGE();
RaisError(@ErrMsg, 1, 1);
End Catch
End
Else
Begin
Print @SQL;
End
End
End
Set @CurrID = @CurrID + 1;
End
Select @MaxID = Max(RoleID), @CurrID = 1
From @Roles;
While @CurrID <= @MaxID
Begin
Select @LoginName = LoginName,
@RoleName = RoleName
From @Roles
Where RoleID = @CurrID;
If Not Exists (Select 1 From sys.server_role_members RM
Inner Join sys.server_principals RoleP
On RoleP.principal_id = RM.role_principal_id
Inner Join sys.server_principals LoginP
On LoginP.principal_id = RM.member_principal_id
Where LoginP.type In ('U', 'G', 'S')
And RoleP.type = 'R'
And RoleP.name = @RoleName
And LoginP.name = @LoginName)
Begin
If @Debug = 0
Begin
Exec sp_addsrvrolemember @rolename = @RoleName,
@loginame = @LoginName;
End
Else
Begin
Print 'Exec sp_addsrvrolemember @rolename = ''' + @RoleName + ''',';
Print ' @loginame = ''' + @LoginName + ''';';
End
End
Set @CurrID = @CurrID + 1;
End
Select @MaxID = Max(PermID), @CurrID = 1
From @Perms;
While @CurrID <= @MaxID
Begin
Select @PermState = PermState,
@PermName = PermName,
@Class = Class,
@LoginName = LoginName,
@MajorID = MajorID,
@SQL = PermState + space(1) + PermName + SPACE(1) +
Case Class When 101 Then 'On Login::' + QUOTENAME(SubLoginName)
When 105 Then 'On ' + ClassDesc + '::' + QUOTENAME(SubEndPointName)
Else '' End +
' To ' + QUOTENAME(LoginName) + ';'
From @Perms
Where PermID = @CurrID;
If Not Exists (Select 1 From sys.server_principals P
Inner Join sys.server_permissions SP On SP.grantee_principal_id = P.principal_id
Where SP.state_desc = @PermState
And SP.permission_name = @PermName
And SP.class = @Class
And P.name = @LoginName
And SP.major_id = @MajorID)
Begin
If @Debug = 0
Begin
Begin Try
Exec sp_executesql @SQL;
End Try
Begin Catch
Set @ErrNumber = ERROR_NUMBER();
Set @ErrSeverity = ERROR_SEVERITY();
Set @ErrState = ERROR_STATE();
Set @ErrProcedure = ERROR_PROCEDURE();
Set @ErrLine = ERROR_LINE();
Set @ErrMsg = ERROR_MESSAGE();
RaisError(@ErrMsg, 1, 1);
End Catch
End
Else
Begin
Print @SQL;
End
End
Set @CurrID = @CurrID + 1;
End
Set NoCount Off;
データベース内のすべてのユーザーを、データベースサーバー上の同様の名前のログインに再リンクすることを常に試みることができます。
ALTER
AUTHORIZATION
ON
SCHEMA::db_owner
TO
dbo
GO
DECLARE @username VARCHAR(64)
DECLARE @sql nvarchar(max)
DECLARE
UserCursor
CURSOR FOR
SELECT
[name]
FROM
sysusers
WHERE
[name] NOT IN('dbo','guest','INFORMATION_SCHEMA','sys','public')
AND
LEFT([name],3) <> 'db_'
AND
[name] NOT LIKE '%]%'
OPEN
UserCursor
FETCH NEXT
FROM
UserCursor
INTO
@username
WHILE @@fetch_status <> -1
BEGIN
SET @sql = 'ALTER USER [' + @username + '] WITH LOGIN=[' + @username + ']'
PRINT @sql
EXEC dbo.sp_executesql @sql;
FETCH NEXT
FROM
UserCursor
INTO
@username
END
CLOSE UserCursor
DEALLOCATE UserCursor
ポスターの問題に対するこの簡単な修正に注目する価値があると思いました。これは、あるサーバーから別のサーバーの開発/テストデータベースに本番データベースを復元するときにSQL Server 2008で実行するスクリプトです。ユーザー名が[セキュリティ]> [データベースのユーザー]にあるが、'login name'
が欠落している場合[全般]タブのユーザープロパティ:
EXEC sp_change_users_login 'Auto_Fix','missingloginnamehere', NULL, 'passwordgoeshere';
MSDNリファレンス ここ この記事では、SQLの新しいバージョンではなく、ALTER USERを使用することを推奨しています。