Як вказати "закрити існуючі з'єднання" в скрипті sql


153

Я активно займаюся розробкою моєї схеми в 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.

Якщо ви клацніть правою кнопкою миші на базі даних на панелі провідника об'єктів і в контекстному меню виберіть завдання «Видалити», з’явиться прапорець «закрити існуючі з'єднання»

Чи є спосіб вказати цей параметр у моєму сценарії?

Відповіді:


247

Ви можете відключити всіх і повернути свої транзакції за допомогою:

alter database [MyDatbase] set single_user with rollback immediate

Після цього ви можете сміливо скинути базу даних :)


8
Я використовував це, але часто замислювався, чи є можливість для іншого користувача потрапити як "єдиний користувач" - це можливо? Можлива альтернатива - ПОДІЛЬНІ ДАТАБАЗИ [MyDatabaseName] ВСТАНОВИТИ ОФЛАЙН З НЕЗАБАВЛЕННЯМ ПОВЕРНЕННЯ
Крістен

9
Користувач у single_user - це ти; якщо ви не відключаєтесь після встановлення одного режиму користувача. Тоді один (1) інший користувач може увійти.
Андомар

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

@AndyM: Так, мультикористувач, мабуть, за замовчуванням
Andomar

2
@Kristen Використовуючи ваш підхід, я виявив, що сервер sql не видаляє файли mdf та ldf. Встановити single_user для мене добре (мені потрібно постійно відтворювати db).
2xMax

36

Перейдіть до студії управління та зробіть усе, що описуєте, лише замість того, щоб натиснути ОК, натисніть на Скрипт. Він покаже код, який він запустить, який ви можете потім включити у свої сценарії.

У цьому випадку потрібно:

ALTER DATABASE [MyDatabase] SET SINGLE_USER WITH ROLLBACK IMMEDIATE
GO

1
Я збирався спробувати відповісти на це питання, роблячи саме те, що ви описуєте (сценарій діалогового вікна "видалити базу даних"), але він не додає рядок ALTER DATABASE до сценарію, якщо ви встановите прапорець "закрити існуючі з'єднання".
Метт Гамільтон

Сценарій, що генерується з майстра, містив для мене рядок "alter database".
псевдонім

Дивно. Яка версія студії управління? Я на 2008 x64.
Метт Гамільтон

Я теж: Microsoft SQL Server Management Studio 10.0.1600.22 Операційна система 6.0.6001
псевдонім

8
Була така ж проблема з тим, що ALTER DATABASE не додається до сценарію. Для того, щоб я його додав до сценарію, я повинен був переконатися, що у мене був запущений процес (активне з'єднання) проти цієї бази даних при створенні сценарію.
Гілберт

16

Згідно з документацією ALTER DATABASE SET , все ж є можливість, що після встановлення бази даних в режим SINGLE_USER ви не зможете отримати доступ до цієї бази даних:

Перш ніж встановити базу даних на SINGLE_USER, перевірте, що для параметра AUTO_UPDATE_STATISTICS_ASYNC встановлено значення OFF. Якщо встановлено значення УВІМКНЕНО, фонова нитка, яка використовується для оновлення статистики, з'єднує базу даних, і ви не зможете отримати доступ до бази даних в режимі однокористування.

Отже, повний скрипт для скидання бази даних із наявними підключеннями може виглядати так:

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відбувається через перевірку "Видалити резервну копію та відновити інформацію історії для баз даних".
Крістіан.К

Якщо встановити прапорець "Закрити існуючі з'єднання", це не призведе до ALTER DATABASE SET SINGLE_USER ...того, що немає поточних з'єднань для закриття.
ahwm

-1

спробуйте цей C # код, щоб скинути вашу базу даних

загальнодоступна статична пустота баз даних DropData (string 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.