Automatically convert contained database to non-contained for replication
June 28, 2017 Leave a comment
This article was recently published on dev.getroadmap.com:
In one of my previous posts, I described how to setup replication to an Azure SQL database. This works like a charm, and I still highly recommend using this when you want to migrate data from an on-premise server (or Azure VM) to a Azure SQL db (PaaS).
But in our environment, we use SQL Server 2016 and contained databases for some of our datasets. Unfortunately (but totally understandable), you can’t setup replication from a contained database. So how do you deal with this? For our use-case, I’ve written a script to automatically change the database from contained to non-contained. And because I’m probably not the only one who needs to do this, I’d like to share it with you.
Steps to take
It might sound a bit difficult, but when you think about it, it’s actually quite easy. To go from a contained database with a user to a non-contained database with a login, you need to take the following steps:
1) Duplicate user as login on server level
2) Drop user on database level
3) Alter database to non-contained
4) Add login to database
The script
Before you start using this, I want to warn you. Using this script on your server(s) or in production is at your own risk. This worked for me, but maybe it doesn’t on your server(s)!
In order to let this script work, you must be able to stop applications and queries from executing on your database. In our case, we can just stop the service(s) that use a specific database (that’s the advantage of micro services). The reason for this is that you must be able to obtain an exclusive lock on the database, in order to switch from contained to non-contained.
If you can manage this, the script below could work for you too:
--==================================================================================================== /* 1 - Duplicate user on instance level as login */ USE master GO CREATE LOGIN [Login non-contained database] WITH PASSWORD=[Password]', DEFAULT_DATABASE=[master], CHECK_EXPIRATION=OFF, CHECK_POLICY=OFF GO --==================================================================================================== /* 2 - Drop user on database level */ USE [Contained database name] GO DROP USER [User contained database] GO --==================================================================================================== /* 3 - Alter database to non-contained */ USE master GO ALTER DATABASE [Contained database name] SET CONTAINMENT = NONE WITH NO_WAIT GO --==================================================================================================== /* 4 - Add login to database */ USE [Non-contained database name] GO CREATE USER [User non-contained database] FOR LOGIN [Login non-contained database] GO ALTER ROLE [db_datareader] ADD MEMBER [User non-contained database] GO ALTER ROLE [db_datawriter] ADD MEMBER [User non-contained database] GO --====================================================================================================
Or, to make it easier to read, an example with actual names:
--==================================================================================================== /* 1 - Duplicate user on instance level as login */ USE master GO CREATE LOGIN [Login_RW] WITH PASSWORD=N'Password123!', DEFAULT_DATABASE=[master], CHECK_EXPIRATION=OFF, CHECK_POLICY=OFF GO --==================================================================================================== /* 2 - Drop user on database level */ USE ContainedDatabase GO DROP USER Login_RW GO --==================================================================================================== /* 3 - Alter database to non-contained */ USE master GO ALTER DATABASE ContainedDatabase SET CONTAINMENT = NONE WITH NO_WAIT GO --==================================================================================================== /* 4 - Add login to database */ USE ContainedDatabase GO CREATE USER Login_RW FOR LOGIN Login_RW GO ALTER ROLE [db_datareader] ADD MEMBER Login_RW GO ALTER ROLE [db_datawriter] ADD MEMBER Login_RW GO --====================================================================================================
Conclusion
Even though I thought that using a contained database could be a big blocking factor for us in the process of migrating data to Azure, it really wasn’t that big of a deal. Especially now that we automated the process, it doesn’t add more than 5 minutes to the process of replicating data to Azure.
