Added a more reliable drop database if exists option#6540
Added a more reliable drop database if exists option#6540ktoliver merged 9 commits intoMicrosoftDocs:livefrom greglow-sdu:patch-73
Conversation
We've had a lengthy discussion in the MVP email list about how to reliably drop a database if it exists. Most methods had issues and simply do not work reliably. This is the best method that we've come up with, and it should be recorded in the documentation for others to use.
|
@greglow-sdu : Thanks for your contribution! The author(s) have been notified to review your proposed change. |
WilliamDAssafMSFT
left a comment
There was a problem hiding this comment.
Thanks @greglow-sdu for the suggestion for this scenario. I can't help but think that this solution is a bit overcomplicated. I believe it can be simplified. I have suggested edits, please review and incorporate.
You should also increment the ms.date: "06/24/2021"
|
Hi William,
Sorry, but really struggling to see from the below changes, what the document would actually then show. Can you preview it, and show me the outcome?
Regards,
Greg
Dr Greg Low
1300SQLSQL (1300 775 775) office | +61 419201410 mobile
SQL Down Under | Web: https://sqldownunder.com<https://sqldownunder.com/> |About me: https://greglow.me
From: William Assaf MSFT ***@***.***>
Sent: Friday, 25 June 2021 5:50 AM
To: MicrosoftDocs/sql-docs ***@***.***>
Cc: Dr Greg Low ***@***.***>; Mention ***@***.***>
Subject: Re: [MicrosoftDocs/sql-docs] Added a more reliable drop database if exists option (#6540)
@WilliamDAssafMSFT requested changes on this pull request.
Thanks @greglow-sdu<https://github.com/greglow-sdu> for the suggestion for this scenario. I can't help but think that this solution is a bit overcomplicated. I believe it can be simplified. I have suggested edits, please review and incorporate.
You should also increment the ms.date: "06/24/2021"
________________________________
In docs/t-sql/statements/drop-database-transact-sql.md<#6540 (comment)>:
@@ -94,10 +94,7 @@ If the database is involved in log shipping, remove log shipping before dropping
The DROP DATABASE statement must run in autocommit mode and is not allowed in an explicit or implicit transaction. Autocommit mode is the default transaction management mode.
-You cannot drop a database currently being used. This means open for reading or writing by any user. One way to remove users from the database is to use ALTER DATABASE to set the database to SINGLE_USER.
-
-> [!WARNING]
-> This is not a fail-proof approach, since first consecutive connection made by any thread will receive the SINGLE_USER thread, causing your connection to fail. Sql server does not provide a built-in way to drop databases under load.
+You cannot drop a database currently being used. This means open for reading or writing by any user. One way to remove users from the database is to use ALTER DATABASE to set the database to SINGLE_USER but you must retain the session lock, to avoid another connection becoming the single user. See the example below.
⬇️ Suggested change
-You cannot drop a database currently being used. This means open for reading or writing by any user. One way to remove users from the database is to use ALTER DATABASE to set the database to SINGLE_USER but you must retain the session lock, to avoid another connection becoming the single user. See the example below.
+> [!WARNING]
+> You cannot drop a database currently being used. This means open for reading or writing by any user. One way to remove users from the database is to use ALTER DATABASE to set the database to SINGLE_USER. In this strategy, you should execute the ALTER DATABASE and DROP DATABASE in the same batch, to avoid another connection claiming single user session allowed. See [Example D below](#dropping-a-database-after-checking-if-it-exists).
________________________________
In docs/t-sql/statements/drop-database-transact-sql.md<#6540 (comment)>:
@@ -161,9 +158,27 @@ The following example removes a database snapshot, named `sales_snapshot0600`, w
DROP DATABASE sales_snapshot0600;
```
+### D. Dropping a database if it exists
+
+The following example removes a database named `Sales` if it exists, by first changing to single user mode.
⬇️ Suggested change
-The following example removes a database named `Sales` if it exists, by first changing to single user mode.
+The following example first checks to see if a database named `Sales` exists. If so, the example changes the database named `Sales` to single-user mode to force disconnect of all other sessions, then drops the database. For more information on SINGLE_USER, see [ALTER DATABASE SET options](alter-database-transact-sql-set-options.md).
________________________________
In docs/t-sql/statements/drop-database-transact-sql.md<#6540 (comment)>:
@@ -161,9 +158,27 @@ The following example removes a database snapshot, named `sales_snapshot0600`, w
DROP DATABASE sales_snapshot0600;
```
+### D. Dropping a database if it exists
+
+The following example removes a database named `Sales` if it exists, by first changing to single user mode.
+
+```sql
+USE tempdb;
+GO
+DECLARE @SQL nvarchar(1000);
+IF EXISTS (SELECT 1 FROM sys.databases WHERE [name] = N'Sales')
+BEGIN
+ SET @SQL = N'USE tempdb;
⬇️ Suggested change
- SET @SQL = N'USE tempdb;
+ SET @SQL = N'ALTER DATABASE [Sales] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
________________________________
In docs/t-sql/statements/drop-database-transact-sql.md<#6540 (comment)>:
@@ -161,9 +158,27 @@ The following example removes a database snapshot, named `sales_snapshot0600`, w
DROP DATABASE sales_snapshot0600;
```
+### D. Dropping a database if it exists
+
+The following example removes a database named `Sales` if it exists, by first changing to single user mode.
+
+```sql
+USE tempdb;
+GO
+DECLARE @SQL nvarchar(1000);
+IF EXISTS (SELECT 1 FROM sys.databases WHERE [name] = N'Sales')
+BEGIN
+ SET @SQL = N'USE tempdb;
+ ALTER DATABASE Sales SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
⬇️ Suggested change
- ALTER DATABASE Sales SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
+ DROP DATABASE [Sales];';
________________________________
In docs/t-sql/statements/drop-database-transact-sql.md<#6540 (comment)>:
@@ -161,9 +158,27 @@ The following example removes a database snapshot, named `sales_snapshot0600`, w
DROP DATABASE sales_snapshot0600;
```
+### D. Dropping a database if it exists
+
+The following example removes a database named `Sales` if it exists, by first changing to single user mode.
+
+```sql
+USE tempdb;
+GO
+DECLARE @SQL nvarchar(1000);
+IF EXISTS (SELECT 1 FROM sys.databases WHERE [name] = N'Sales')
+BEGIN
+ SET @SQL = N'USE tempdb;
+ ALTER DATABASE Sales SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
+ USE master;
⬇️ Suggested change
- USE master;
________________________________
In docs/t-sql/statements/drop-database-transact-sql.md<#6540 (comment)>:
@@ -161,9 +158,27 @@ The following example removes a database snapshot, named `sales_snapshot0600`, w
DROP DATABASE sales_snapshot0600;
```
+### D. Dropping a database if it exists
+
+The following example removes a database named `Sales` if it exists, by first changing to single user mode.
+
+```sql
+USE tempdb;
+GO
+DECLARE @SQL nvarchar(1000);
+IF EXISTS (SELECT 1 FROM sys.databases WHERE [name] = N'Sales')
+BEGIN
+ SET @SQL = N'USE tempdb;
+ ALTER DATABASE Sales SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
+ USE master;
+ DROP DATABASE Sales;';
⬇️ Suggested change
- DROP DATABASE Sales;';
________________________________
In docs/t-sql/statements/drop-database-transact-sql.md<#6540 (comment)>:
+### D. Dropping a database if it exists
+
+The following example removes a database named `Sales` if it exists, by first changing to single user mode.
+
+```sql
+USE tempdb;
+GO
+DECLARE @SQL nvarchar(1000);
+IF EXISTS (SELECT 1 FROM sys.databases WHERE [name] = N'Sales')
+BEGIN
+ SET @SQL = N'USE tempdb;
+ ALTER DATABASE Sales SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
+ USE master;
+ DROP DATABASE Sales;';
+ EXEC (@SQL);
+ USE tempdb;
⬇️ Suggested change
- USE tempdb;
________________________________
In docs/t-sql/statements/drop-database-transact-sql.md<#6540 (comment)>:
@@ -161,9 +158,27 @@ The following example removes a database snapshot, named `sales_snapshot0600`, w
DROP DATABASE sales_snapshot0600;
```
+### D. Dropping a database if it exists
⬇️ Suggested change
-### D. Dropping a database if it exists
+### D. Dropping a database after checking if it exists
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub<#6540 (review)>, or unsubscribe<https://github.com/notifications/unsubscribe-auth/AEN7CKZOQ72YSO6CY3TL57DTUOD7RANCNFSM47GXN4HA>.
|
|
Yes sorry the changes had to be made line by line so that they could be easily accepted by your review.
The sample:
USE tempdb;
GO
DECLARE @SQL nvarchar(1000);
IF EXISTS (SELECT 1 FROM sys.databases WHERE [name] = N'dropdb')
BEGIN
SET @SQL = N'ALTER DATABASE dropdb SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
DROP DATABASE dropdb;';
EXEC (@SQL);
END;
|
|
Hi William,
No, unfortunately that won’t work.
You need to be in the target DB when you issue the ALTER, otherwise you don’t guarantee you have the lock (and not some other process), then you can’t be in the target DB to issue the drop.
I’ve spelled it out here: https://blog.greglow.com/2021/06/24/reliably-dropping-a-sql-server-database-if-it-exists/
I can jump on a call to explain it if necessary.
Regards,
Greg
Dr Greg Low
1300SQLSQL (1300 775 775) office | +61 419201410 mobile
SQL Down Under | Web: https://sqldownunder.com<https://sqldownunder.com/> |About me: https://greglow.me
From: William Assaf MSFT ***@***.***>
Sent: Friday, 25 June 2021 8:46 AM
To: MicrosoftDocs/sql-docs ***@***.***>
Cc: Dr Greg Low ***@***.***>; Mention ***@***.***>
Subject: Re: [MicrosoftDocs/sql-docs] Added a more reliable drop database if exists option (#6540)
Yes sorry the changes had to be made line by line so that they could be easily accepted by your review.
The sample:
USE tempdb;
GO
DECLARE @SQL nvarchar(1000);
IF EXISTS (SELECT 1 FROM sys.databases WHERE [name] = N'dropdb')
BEGIN
SET @SQL = N'ALTER DATABASE dropdb SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
DROP DATABASE dropdb;';
EXEC (@SQL);
END;
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub<#6540 (comment)>, or unsubscribe<https://github.com/notifications/unsubscribe-auth/AEN7CK2RVPX4OTFAHQ2D2G3TUOYSDANCNFSM47GXN4HA>.
|
@greglow-sdu Do you have a sample script or scenario that reproduces the For example, You should see that the SESSION has still requested a SHARED DATABASE lock. Trying to |
|
Hi William,
I know the theory and I wish I could build a reliable repro. That’s the problem. It’s really hard to duplicate, but it’s really nasty when it fails.
The doco used to show code that did exactly that. The problem is that most people don’t run this sort of code often. When we were building the SQL courseware for Microsoft, we were running this type of code all the time. I had it fail occasionally. The testing team in Shanghai had it fail occasionally. Students doing the courses had it fail often enough that we wrote them instructions into the labs in the courseware about what to do if it failed.
What seemed to be happening is that because the script dropped and recreated the DB, the Intellisense in Object Explorer in SSMS was connecting to the DB to scan the syntax further down the script i.e. the part after where the DB was recreated. When you set it to single user, sometimes, that other thread was the single user, not you. So just sometimes, the drop would fail.
The trick seems to be that if you’re in the context of the target DB when you set it to single user, then nothing else can grab it. But you can’t drop it from in there, so you have to change to a different. At least if you do it that way, it seems to always work.
My real preference is that I just wish they’d fix the DROP DATABASE IF EXISTS statement so that it worked. As it is today, it’s completely pointless.
Regards,
Greg
Dr Greg Low
1300SQLSQL (1300 775 775) office | +61 419201410 mobile
SQL Down Under | Web: https://sqldownunder.com<https://sqldownunder.com/> |About me: https://greglow.me
From: William Assaf MSFT ***@***.***>
Sent: Friday, 25 June 2021 9:18 AM
To: MicrosoftDocs/sql-docs ***@***.***>
Cc: Dr Greg Low ***@***.***>; Mention ***@***.***>
Subject: Re: [MicrosoftDocs/sql-docs] Added a more reliable drop database if exists option (#6540)
Because you were in the master database when you issued the ALTER, you don't know that you are the single user. So, periodically, that would fail too.
@greglow-sdu<https://github.com/greglow-sdu> Do you have a sample script or scenario that reproduces the ALTER DATABASE ... SET SINGLE_USER WITH ROLLBACK IMMEDIATE not claiming a lock on the single-user database, even if called from another database?
For example,
USE tempdb;
ALTER DATABASE dropdb SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
SELECT db_name(resource_database_id), request_session_id, request_type, * FROM sys.dm_tran_locks;
You should see that the SESSION has still requested a SHARED DATABASE lock. Trying to USE dropdb from another session fails with Msg 924, Level 14, State 1, Line 1 Database 'dropdb' is already open and can only have one user at a time, and the DROP DATABASE succeeds.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub<#6540 (comment)>, or unsubscribe<https://github.com/notifications/unsubscribe-auth/AEN7CKZBF5LIBEZ3AD4EQRLTUO4LRANCNFSM47GXN4HA>.
|
|
Actually if I had that in the pull request, that tempdb was in error. The first USE in the dynamic SQL should have been to Sales.
It should have been:
+USE tempdb;
+GO
+DECLARE @SQL nvarchar(1000);
+IF EXISTS (SELECT 1 FROM sys.databases WHERE [name] = N'Sales')
+BEGIN
+ SET @SQL = N'USE Sales;
+ ALTER DATABASE Sales SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
+ USE master;
+ DROP DATABASE Sales;';
+ EXEC (@SQL);
Regards,
Greg
Dr Greg Low
1300SQLSQL (1300 775 775) office | +61 419201410 mobile
SQL Down Under | Web: https://sqldownunder.com<https://sqldownunder.com/> |About me: https://greglow.me
From: William Assaf MSFT ***@***.***>
Sent: Friday, 25 June 2021 10:00 AM
To: MicrosoftDocs/sql-docs ***@***.***>
Cc: Dr Greg Low ***@***.***>; Mention ***@***.***>
Subject: Re: [MicrosoftDocs/sql-docs] Added a more reliable drop database if exists option (#6540)
@WilliamDAssafMSFT commented on this pull request.
________________________________
In docs/t-sql/statements/drop-database-transact-sql.md<#6540 (comment)>:
+### D. Dropping a database if it exists
+
+The following example removes a database named `Sales` if it exists, by first changing to single user mode.
+
+```sql
+USE tempdb;
+GO
+DECLARE @SQL nvarchar(1000);
+IF EXISTS (SELECT 1 FROM sys.databases WHERE [name] = N'Sales')
+BEGIN
+ SET @SQL = N'USE tempdb;
+ ALTER DATABASE Sales SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
+ USE master;
+ DROP DATABASE Sales;';
+ EXEC (@SQL);
+ USE tempdb;
This is unnecessary and confusing. I see your note about it in the blog but unnecessary for this context.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub<#6540 (comment)>, or unsubscribe<https://github.com/notifications/unsubscribe-auth/AEN7CK76X3QIRMBXKPOMDETTUPBI3ANCNFSM47GXN4HA>.
|
|
@greglow-sdu I suppose it couldn't hurt to have the extra USE lines in there aside from confusion. I don't understand how, even if something else claimed the session after the ALTER DATABASE, how it couldn't then be seized again when the second USE relinquishes the single-user session. We'd need to do a better job of explaining them justified by a mysterious, undocumented edge case. In any case, line 171 still needs to change, I've proposed that. Go ahead and accept my revisions and review yourself. |
|
I’ve added one more comment.
Line 171 needs to be USE Sales; not USE master;
It needs to change into the target DB.
Regards,
Greg
Dr Greg Low
1300SQLSQL (1300 775 775) office | +61 419201410 mobile
SQL Down Under | Web: https://sqldownunder.com<https://sqldownunder.com/> |About me: https://greglow.me
From: William Assaf MSFT ***@***.***>
Sent: Friday, 25 June 2021 10:11 AM
To: MicrosoftDocs/sql-docs ***@***.***>
Cc: Dr Greg Low ***@***.***>; Mention ***@***.***>
Subject: Re: [MicrosoftDocs/sql-docs] Added a more reliable drop database if exists option (#6540)
@greglow-sdu<https://github.com/greglow-sdu> I suppose it couldn't hurt to have the extra USE lines in there aside from confusion. I don't understand how, even if something else claimed the session after the ALTER DATABASE, how it couldn't then be seized again when the second USE relinquishes the single-user session. We'd need to do a better job of explaining them justified by a mysterious, undocumented edge case. In any case, line 171 still needs to change, I've proposed that. Go ahead and accept my revisions and review yourself.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub<#6540 (comment)>, or unsubscribe<https://github.com/notifications/unsubscribe-auth/AEN7CK6QTAL5OEOUOP2VX2TTUPCPVANCNFSM47GXN4HA>.
|
|
@WilliamDAssafMSFT : Thanks for your contribution! The author(s) have been notified to review your proposed change. |
|
@WilliamDAssafMSFT : Thanks for your contribution! The author(s) have been notified to review your proposed change. |
|
@WilliamDAssafMSFT : Thanks for your contribution! The author(s) have been notified to review your proposed change. |
|
@WilliamDAssafMSFT : Thanks for your contribution! The author(s) have been notified to review your proposed change. |
|
@greglow-sdu I've approved my suggestion commits, take a look. |
|
@WilliamDAssafMSFT : Thanks for your contribution! The author(s) have been notified to review your proposed change. |
|
Thanks @ktoliver, the merge conflict resolution does that sometimes. |
@greglow-sdu What do you think? |
|
Looks good thanks William
Regards,
Greg
Dr Greg Low
1300SQLSQL (1300 775 775) office | +61 419201410 mobile
SQL Down Under | Web: https://sqldownunder.com<https://sqldownunder.com/> |About me: https://greglow.me
From: William Assaf MSFT ***@***.***>
Sent: Tuesday, 29 June 2021 8:12 AM
To: MicrosoftDocs/sql-docs ***@***.***>
Cc: Dr Greg Low ***@***.***>; Mention ***@***.***>
Subject: Re: [MicrosoftDocs/sql-docs] Added a more reliable drop database if exists option (#6540)
FYI, here's a snapshot of the diff (the diff isn't visible in GitHub):
[image]<https://user-images.githubusercontent.com/19416435/123455782-f9f00700-d596-11eb-8c5a-74082f32a449.png>
We'll wait for a #sign-off to merge.
@greglow-sdu<https://github.com/greglow-sdu> What do you think?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub<#6540 (comment)>, or unsubscribe<https://github.com/notifications/unsubscribe-auth/AEN7CK7OE4GN5GYSVOWYVRLTVDXUFANCNFSM47GXN4HA>.
|
|
@greglow-sdu: I'm sorry - only the author of this article, @WilliamDAssafMSFT, can sign off on your changes. But we do have an exception process - if you are on the Microsoft content or product team for this product area, you can ask the PR review team to review and merge it by sending mail to the techdocprs alias. |
|
#sign-off |

We've had a lengthy discussion in the MVP email list about how to reliably drop a database if it exists. Most methods had issues and simply do not work reliably. This is the best method that we've come up with, and it should be recorded in the documentation for others to use.