Come posso specificare "chiudi connessioni esistenti" nello script sql


153

Sto facendo uno sviluppo attivo sul mio schema in SQL Server 2008 e spesso desidero rieseguire il mio script di database drop / create. Quando corro

USE [master]
GO

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

Ricevo spesso questo errore

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

Se fai clic con il pulsante destro del mouse sul database nel riquadro Esplora oggetti e selezioni l'attività Elimina dal menu di scelta rapida, è presente una casella di controllo che consente di "chiudere le connessioni esistenti"

C'è un modo per specificare questa opzione nel mio script?

Risposte:


247

Puoi disconnettere tutti e ripristinare le loro transazioni con:

alter database [MyDatbase] set single_user with rollback immediate

Successivamente, puoi rilasciare il database in modo sicuro :)


8
L'ho usato ma spesso mi chiedevo se ci fosse una finestra di opportunità per un altro utente come "singolo utente" - è possibile? La possibile alternativa è ALTER DATABASE [MyDatabaseName] SET OFFLINE CON ROLLBACK IMMEDIATO
Kristen

9
L'utente in single_user sei tu; a meno che non ti disconnetti dopo aver impostato la modalità utente singolo. Quindi un (1) altro utente può accedere.
Andomar,

Una volta che hai lasciato cadere il database, se ne crei uno nuovo con lo stesso nome, suppongo che sarà in modalità multiutente? Quindi non è necessario eseguire: alter database [MyDatbase] set multi_user
AndyM

@AndyM: Sì, multi_user è probabilmente l'impostazione predefinita
Andomar

2
@Kristen Usando il tuo approccio ho scoperto che il server sql non rimuove i file mdf e ldf. Set single_user funziona bene per me (devo ricreare costantemente il db).
2x Max

36

Vai a Management Studio e fai tutto quello che descrivi, solo invece di fare clic su OK, fai clic su Script. Mostrerà il codice che verrà eseguito che sarà quindi possibile incorporare nei propri script.

In questo caso, vuoi:

ALTER DATABASE [MyDatabase] SET SINGLE_USER WITH ROLLBACK IMMEDIATE
GO

1
Stavo per provare a rispondere a questa domanda facendo esattamente ciò che descrivi (scripting della finestra di dialogo "elimina database") ma non aggiunge la riga ALTER DATABASE allo script se selezioni la casella di controllo "chiudi connessioni esistenti".
Matt Hamilton,

Lo script generato dalla procedura guidata includeva per me la riga "alter database".
nick

Strano. Quale versione di Management Studio? Sono sul 2008 x64.
Matt Hamilton,

Anche a me: Microsoft SQL Server Management Studio 10.0.1600.22 Sistema operativo 6.0.6001
nick

8
Ha avuto lo stesso problema con ALTER DATABASE non aggiunto allo script. Per poterlo aggiungere allo script ho dovuto assicurarmi di avere un processo in esecuzione (connessione attiva) contro quel database quando lo script è stato generato.
Gilbert,

16

Secondo la documentazione ALTER DATABASE SET , esiste ancora la possibilità che dopo aver impostato un database in modalità SINGLE_USER non sarà possibile accedere a quel database:

Prima di impostare il database su SINGLE_USER, verificare che l'opzione AUTO_UPDATE_STATISTICS_ASYNC sia impostata su OFF. Se impostato su ON, il thread in background utilizzato per aggiornare le statistiche prende una connessione al database e non sarà possibile accedere al database in modalità utente singolo.

Quindi, uno script completo per eliminare il database con connessioni esistenti potrebbe essere simile al seguente:

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]


2

Ho provato quello che dice hgmnz su SQL Server 2012.

Gestione creata per me:

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
Ciò non chiuderà le connessioni attive.
Jens,

Assicurati di aver selezionato "Chiudi connessioni esistenti"; Se doni la ROLLBACK IMMEDIATEdichiarazione sarà inclusa. La sp_delete_database_backuphistoryderiva dal controllo del "backup cancellare e ripristinare le informazioni della cronologia per i database".
Christian.K,

La selezione di "Chiudi connessioni esistenti" non genera ALTER DATABASE SET SINGLE_USER ...se non ci sono connessioni correnti da chiudere.
Ahwm,

-1

prova questo codice C # per eliminare il tuo database

DropD Database vuoto statico pubblico (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();
            }
        }
    }
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.