Como especificar "fechar conexões existentes" no script sql

153

Estou desenvolvendo ativamente meu esquema no SQL Server 2008 e frequentemente desejo executar novamente meu script de soltar / criar banco de dados. Quando eu corro

USE [master]
GO

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

Costumo receber este erro

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

Se você clicar com o botão direito do mouse no banco de dados no painel do explorador de objetos e selecionar a tarefa Excluir no menu de contexto, há uma caixa de seleção para "fechar conexões existentes"

Existe uma maneira de especificar esta opção no meu script?

usuario
fonte

Respostas:

247

Você pode desconectar todos e reverter suas transações com:

alter database [MyDatbase] set single_user with rollback immediate

Depois disso, você pode soltar o banco de dados com segurança :)

Andomar
fonte
8
Eu usei isso, mas sempre me perguntei se havia uma janela de oportunidade para outro usuário entrar como "usuário único" - isso é possível? Alternativa possível é ALTER DATABASE [MyDatabaseName] SET offline com ROLLBACK IMEDIATA
Kristen
9
O usuário em single_user é você; a menos que você se desconecte após definir o modo de usuário único. Então, um (1) outro usuário pode fazer logon.
Andomar 10/11/2009
Depois de soltar o banco de dados, se você criar um novo com o mesmo nome, presumo que ele estará no modo multiusuário? Então você não tem que correr: alter database [MyDatbase] conjunto MULTI_USER
AndyM
@AndyM: Sim, MULTI_USER é provavelmente o padrão
Andomar
2
@ Kristen Usando sua abordagem, descobri que o servidor sql não remove os arquivos mdf e ldf. Definir single_user funciona bem para mim (preciso recriar constantemente o banco de dados).
2xMax 15/03
36

Vá para o Management Studio e faça tudo o que você descreve, apenas em vez de clicar em OK, clique em Script. Ele mostrará o código que será executado, que você poderá incorporar em seus scripts.

Nesse caso, você deseja:

ALTER DATABASE [MyDatabase] SET SINGLE_USER WITH ROLLBACK IMMEDIATE
GO
hgmnz
fonte
1
Eu tentaria responder a essa pergunta fazendo exatamente o que você descreve (criando um script na caixa de diálogo "excluir banco de dados"), mas ela não adiciona a linha ALTER DATABASE ao script se você marcar a caixa de seleção "fechar conexões existentes".
Matt Hamilton
O script gerado pelo assistente incluiu a linha 'alter database' para mim.
nick
Esquisito. Qual versão do Management Studio? Estou em 2008 x64.
Matt Hamilton
Eu também: Microsoft SQL Server Management Studio 10.0.1600.22 Sistema operacional 6.0.6001
nick
8
Teve o mesmo problema com ALTER DATABASE não sendo adicionado ao script. Para que eu possa adicioná-lo ao script, tive que verificar se havia um processo em execução (conexão ativa) nesse banco de dados quando o script foi gerado.
Gilbert
16

De acordo com a documentação do ALTER DATABASE SET , ainda existe a possibilidade de que, após definir um banco de dados no modo SINGLE_USER, você não possa acessar esse banco de dados:

Antes de definir o banco de dados como SINGLE_USER, verifique se a opção AUTO_UPDATE_STATISTICS_ASYNC está definida como OFF. Quando definido como LIGADO, o encadeamento em segundo plano usado para atualizar estatísticas faz uma conexão com o banco de dados e você não poderá acessar o banco de dados no modo de usuário único.

Portanto, um script completo para descartar o banco de dados com conexões existentes pode ser assim:

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
fonte
3

Eu sei que é tarde demais, mas pode ser que ajude alguém. ao usar isso, coloque seu banco de dados offline

ALTER DATABASE dbname SET OFFLINE
Abhishek Upadhyay
fonte
observação: depois de "soltar banco de dados offline", o arquivo Mdf não caiu! stackoverflow.com/questions/33154141/…
bob217 27/03
2

Eu tentei o que hgmnz diz no SQL Server 2012.

Gerenciamento criado para mim:

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
fonte
4
Isso não fechará as conexões ativas.
Jens
Verifique se você marcou "Fechar conexões existentes"; Se você ROLLBACK IMMEDIATEusar, a declaração será incluída. Isso sp_delete_database_backuphistoryvem da verificação de "Excluir informações de histórico de backup e restauração de bancos de dados".
Christian.K
A seleção de "Fechar conexões existentes" não gera ALTER DATABASE SET SINGLE_USER ...se não houver conexões atuais para fechar.
ahwm 23/02
-1

tente este código C # para descartar seu banco de dados

DropDatabases públicos nulos estáticos (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();
            }
        }
    }
Shailesh Tiwari
fonte