Как мне указать «закрыть существующие подключения» в сценарии SQL


154

Я активно занимаюсь разработкой своей схемы в SQL Server 2008 и часто хочу перезапустить сценарий удаления / создания базы данных. Когда я бегу

USE [master]
GO

IF  EXISTS (SELECT name FROM sys.databases WHERE name = N'MyDatabase')
DROP DATABASE [MyDatabase]
GO

Я часто получаю эту ошибку

Msg 3702, Level 16, State 4, Line 3
Cannot drop database "MyDatabase" because it is currently in use.

Если щелкнуть правой кнопкой мыши базу данных на панели обозревателя объектов и выбрать задачу «Удалить» из контекстного меню, появится флажок для «закрытия существующих подключений».

Есть ли способ указать эту опцию в моем скрипте?

Ответы:


248

Вы можете отключить всех и откатить свои транзакции с помощью:

alter database [MyDatbase] set single_user with rollback immediate

После этого вы можете смело удалять базу данных :)


8
Я использовал это, но часто задавался вопросом, было ли окно для другого пользователя, чтобы войти как "единственный пользователь" - это возможно? Возможная альтернатива - ALTER DATABASE [MyDatabaseName], установленный в автономном режиме с немедленным откликом
Кристен

9
Пользователь в single_user - это вы; если вы не отключите после установки однопользовательского режима. Тогда один (1) другой пользователь может войти в систему.
Andomar

После того, как вы удалили базу данных, если вы создадите новую с тем же именем, я предполагаю, что она будет в режиме multi_user? Поэтому вам не нужно запускать: alter database [MyDatbase] set multi_user
AndyM

@AndyM: Да, multi_user, вероятно, используется по умолчанию
Andomar

2
@ Кристен Используя ваш подход, я обнаружил, что сервер sql не удаляет файлы mdf и ldf. Set single_user прекрасно работает для меня (мне нужно постоянно пересоздавать БД).
2xMax

36

Зайдите в Management Studio и сделайте все, что вы описываете, только вместо того, чтобы нажимать OK, нажмите Script. Он покажет код, который он будет запускать, который вы затем сможете включить в свои скрипты.

В этом случае вы хотите:

ALTER DATABASE [MyDatabase] SET SINGLE_USER WITH ROLLBACK IMMEDIATE
GO

1
Я собирался попытаться ответить на этот вопрос, выполнив в точности то, что вы описываете (сценарий диалога «удалить базу данных»), но он не добавляет строку ALTER DATABASE в сценарий, если вы установите флажок «закрыть существующие подключения».
Мэтт Гамильтон

Сценарий, генерируемый из мастера, включал в себя строку «изменить базу данных» для меня.
Ник

Weird. Какая версия Management Studio? Я на 2008 х64.
Мэтт Гамильтон

Я тоже: Microsoft SQL Server Management Студия 10.0.1600.22 Операционная система 6.0.6001
ник

8
Была такая же проблема с ALTER DATABASE, которая не была добавлена ​​в скрипт. Чтобы добавить его в сценарий, я должен был убедиться, что у меня запущен процесс (активное соединение) для этой базы данных при создании сценария.
Гилберт

16

Согласно документации ALTER DATABASE SET , все еще существует вероятность того, что после установки базы данных в режим SINGLE_USER вы не сможете получить доступ к этой базе данных:

Прежде чем установить для базы данных значение SINGLE_USER, убедитесь, что для параметра AUTO_UPDATE_STATISTICS_ASYNC установлено значение OFF. Если установлено значение ON, фоновый поток, используемый для обновления статистики, подключается к базе данных, и вы не сможете получить доступ к базе данных в однопользовательском режиме.

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

DECLARE @dbId int
DECLARE @isStatAsyncOn bit
DECLARE @jobId int
DECLARE @sqlString nvarchar(500)

SELECT @dbId = database_id,
       @isStatAsyncOn = is_auto_update_stats_async_on
FROM sys.databases
WHERE name = 'db_name'

IF @isStatAsyncOn = 1
BEGIN
    ALTER DATABASE [db_name] SET  AUTO_UPDATE_STATISTICS_ASYNC OFF

    -- kill running jobs
    DECLARE jobsCursor CURSOR FOR
    SELECT job_id
    FROM sys.dm_exec_background_job_queue
    WHERE database_id = @dbId

    OPEN jobsCursor

    FETCH NEXT FROM jobsCursor INTO @jobId
    WHILE @@FETCH_STATUS = 0
    BEGIN
        set @sqlString = 'KILL STATS JOB ' + STR(@jobId)
        EXECUTE sp_executesql @sqlString
        FETCH NEXT FROM jobsCursor INTO @jobId
    END

    CLOSE jobsCursor
    DEALLOCATE jobsCursor
END

ALTER DATABASE [db_name] SET  SINGLE_USER WITH ROLLBACK IMMEDIATE

DROP DATABASE [db_name]

3

Я знаю, что уже слишком поздно, но, может быть, кому-то это поможет. при использовании этого взять вашу базу данных в автономном режиме

ALTER DATABASE dbname SET OFFLINE

примечание: после «удаления автономной базы данных» файл Mdf не удаляется! stackoverflow.com/questions/33154141/...
bob217

2

Я попробовал то, что сказал hgmnz на SQL Server 2012.

Управление создано для меня:

EXEC msdb.dbo.sp_delete_database_backuphistory @database_name = N'MyDataBase'
GO
USE [master]
GO
/****** Object:  Database [MyDataBase]    Script Date: 09/09/2014 15:58:46 ******/
DROP DATABASE [MyDataBase]
GO

4
Это не закроет активные соединения.
Дженс

Убедитесь, что вы отметили «Закрыть существующие подключения»; Если вы делаете это, ROLLBACK IMMEDIATEзаявление будет включено. Это sp_delete_database_backuphistoryпроисходит из-за проверки «Удаление резервной копии и восстановление истории информации для баз данных».
Christian.K

Проверка «Закрыть существующие подключения» не генерирует, ALTER DATABASE SET SINGLE_USER ...если нет текущих подключений для закрытия.
ahwm

-1

попробуйте этот код C #, чтобы удалить вашу базу данных

public static void DropDatabase (строка dataBase) {

        string sql =  "ALTER DATABASE "  + dataBase + "SET SINGLE_USER WITH ROLLBACK IMMEDIATE" ;

        using (System.Data.SqlClient.SqlConnection connection = new System.Data.SqlClient.SqlConnection(ConfigurationManager.ConnectionStrings["DBRestore"].ConnectionString))
        {
            connection.Open();
            using (System.Data.SqlClient.SqlCommand command = new System.Data.SqlClient.SqlCommand(sql, connection))
            {
                command.CommandType = CommandType.Text;
                command.CommandTimeout = 7200;
                command.ExecuteNonQuery();
            }
            sql = "DROP DATABASE " + dataBase;
            using (System.Data.SqlClient.SqlCommand command = new System.Data.SqlClient.SqlCommand(sql, connection))
            {
                command.CommandType = CommandType.Text;
                command.CommandTimeout = 7200;
                command.ExecuteNonQuery();
            }
        }
    }
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.