Как удалить базу данных в режиме Single_User

12

Как мне удалить базу данных, которая отображается в DatabaseName (Single User)качестве ее имени?

Когда я пытаюсь удалить его, я получаю следующую ошибку:

Ошибка изменения для базы данных «DatabaseName». (Microsoft.SqlServer.Smo)

Оператор ALTER DATABASE не выполнен. (Microsoft SQL Server, ошибка: 5064)

Я попытался выполнить ALTERниже и все еще есть та же проблема.

ALTER DATABASE [DatabaseName] SET MULTI_USER WITH NO_WAIT
Прасад Канапарти
источник

Ответы:

23

Если вы собираетесь удалить базу данных, вы должны быть единственным подключением к этой базе данных. Если есть какие-либо другие соединения, вы не можете сбросить их. Из сообщения об ошибке (эта ошибка означает, что ваша база данных находится в режиме Single_User, но соединение уже установлено, поэтому вы не можете подключиться), я предполагаю, что вы пытались установить его в режим Single_User, а затем пытались выполнить удаление, но либо вы захватил соединение, о котором вы не знали, или какой-то другой процесс. Тот факт, что перезапуск SSMS сработал для вас, говорит мне о том, что вы, вероятно, захватили это соединение. Вот как вы можете это исправить.

Логически вы должны перевести базу данных обратно в режим multi_user, чтобы затем снова перевести ее в режим single_user (но на этот раз вы будете контролировать одно разрешенное соединение и сбросить базу данных до того, как что-то еще подключится), и тогда ваша база данных будет уйти

В коде вот как вам нужно это сделать ( но сначала закройте окна запросов, которые связаны с этой базой данных. Перезапустите SSMS и убедитесь, что вы не выбираете эту базу данных в браузере объектов ):

-- Then attempt to take your database to multi_user mode, do this from master
USE MASTER 
GO

ALTER DATABASE myDatabaseName 
SET multi_user WITH ROLLBACK IMMEDIATE
GO

-- Now put it into single_user mode and drop it. Use Rollback Immediate to disconnect any sessions and rollback their transactions. Safe since you are about to drop the DB.
ALTER DATABASE myDatabaseName
SET SINGLE_USER WITH ROLLBACK IMMEDIATE
GO

DROP DATABASE myDatabaseName
GO
Майк Уолш
источник
Это решение не будет работать, если база данных уже находится в однопользовательском режиме, и вы пытаетесь получить к ней доступ из другого соединения.
Максим Пауков
4
Правильно, Максим. Вот почему я сказал, что мое предположение здесь основано на предоставленной информации и самом ответе OP на самом деле то, с открытым соединением, вероятно, через проводник объектов или окно запроса ... Если оно было открыто каким-то другим способом другой пользователь, тогда вам нужно будет найти одно соединение, которое украло разрешенное одиночное соединение, а затем прекратить сеанс этого соединения, и выполнить действия, описанные выше ..
Майк Уолш
13

Если вы попытаетесь получить доступ к базе данных, которая уже находится в однопользовательском режиме, вам сначала нужно закрыть все подключения к базе данных, в противном случае вы получите сообщение об ошибке:

Сообщение 5064, уровень 16, состояние 1, строка 1 В настоящее время невозможно изменить состояние или параметры базы данных DatabaseName. База данных находится в однопользовательском режиме, и пользователь в настоящее время подключен к ней. Сообщение 5069, уровень 16, состояние 1, строка 1: оператор ALTER DATABASE не выполнен.

Следующий запрос убивает процессы доступа к базе данных:

-- Create the sql to kill the active database connections  
declare @execSql varchar(1000), @databaseName varchar(100)  
-- Set the database name for which to kill the connections  
set @databaseName = 'DatabaseName'  

set @execSql = ''   
select  @execSql = @execSql + 'kill ' + convert(char(10), spid) + ' '  
from    master.dbo.sysprocesses  
where   db_name(dbid) = @databaseName  
     and  
     DBID <> 0  
     and  
     spid <> @@spid  
exec(@execSql)
GO

Тогда вы сможете вернуть базу данных в многопользовательский режим, как обычно:

ALTER DATABASE 'DatabaseName' SET MULTI_USER
Максим Пауков
источник
2
Это очень, очень громоздкое решение, которое приравнивается к разочаровывающей игре в крота на занятой системе. Чтобы выгнать всех пользователей, гораздо проще в использовании, ALTER DATABASE SET SINGLE_USER WITH ROLLBACK IMMEDIATEкак показывает ответ Майка.
Аарон Бертран
1
@AaronBertrand Решение Майка не будет работать, если база данных уже находится в однопользовательском режиме, и вы пытаетесь получить к ней доступ из другого соединения.
Максим Пауков
2
Правильно, если это так, он должен будет найти сессии, как вы наметили. Однако, если соединение, которое устанавливает базу данных в single_user, является его собственным ...
Аарон Бертран