Как мне указать «закрыть существующие подключения» в сценарии 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

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

Andomar
источник
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
hgmnz
источник
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]
AlexD
источник
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
Deiwys
источник
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();
            }
        }
    }
Шайлеш Тивари
источник