Bagaimana cara menentukan "tutup koneksi yang ada" dalam skrip sql

153

Saya sedang melakukan pengembangan aktif pada skema saya di SQL Server 2008 dan sering ingin menjalankan kembali drop / buat skrip database saya. Ketika saya berlari

USE [master]
GO

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

Saya sering mendapatkan kesalahan ini

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

Jika Anda mengklik kanan pada database di panel objek explorer dan memilih tugas Hapus dari menu konteks, ada kotak centang yang untuk "menutup koneksi yang ada"

Apakah ada cara untuk menentukan opsi ini dalam skrip saya?

nick
sumber

Jawaban:

247

Anda dapat memutuskan koneksi semua orang dan memutar kembali transaksi mereka dengan:

alter database [MyDatbase] set single_user with rollback immediate

Setelah itu, Anda dapat dengan aman menjatuhkan basis data :)

Andomar
sumber
8
Saya telah menggunakan ini tetapi sering bertanya-tanya apakah ada jendela peluang bagi pengguna lain untuk masuk sebagai "pengguna tunggal" - apakah itu mungkin? Alternatif yang mungkin adalah ALTER DATABASE [MyDatabaseName] SET OFFLINE DENGAN ROLLBACK SEGERA
Kristen
9
Pengguna di single_user adalah Anda; kecuali jika Anda memutuskan setelah mengatur mode pengguna tunggal. Kemudian satu (1) pengguna lain dapat masuk.
Andomar
Setelah Anda menjatuhkan database, jika Anda membuat yang baru dengan nama yang sama saya kira itu akan berada dalam mode multi_user? Jadi Anda tidak harus menjalankan: ubah basis data [MyDatbase] set multi_user
AndyM
@AndyM: Ya, multi_user mungkin default
Andomar
2
@ Kristen Menggunakan pendekatan Anda Saya menemukan server sql tidak menghapus file mdf dan ldf. Set single_user berfungsi dengan baik untuk saya (saya harus terus-menerus membuat ulang db).
2xMax
36

Buka studio manajemen dan lakukan semua yang Anda gambarkan, hanya alih-alih mengklik OK, klik pada Skrip. Ini akan menunjukkan kode yang akan dijalankan yang kemudian dapat Anda masukkan ke dalam skrip Anda.

Dalam hal ini, Anda ingin:

ALTER DATABASE [MyDatabase] SET SINGLE_USER WITH ROLLBACK IMMEDIATE
GO
hgmnz
sumber
1
Saya akan mencoba menjawab pertanyaan ini dengan melakukan apa yang Anda jelaskan (menulis dialog "hapus basis data") tetapi tidak menambahkan baris ALTER DATABASE ke skrip jika Anda mencentang kotak centang "tutup koneksi yang ada".
Matt Hamilton
Pembuatan skrip dari wizard menyertakan baris 'alter database' untuk saya.
nick
Aneh. Versi Management Studio yang mana? Saya menggunakan 2008 x64.
Matt Hamilton
Saya juga: Microsoft SQL Server Management Studio 10.0.1600.22 Sistem Operasi 6.0.6001
nick
8
Punya masalah yang sama dengan ALTER DATABASE tidak ditambahkan ke skrip. Agar saya dapat menambahkannya ke skrip saya harus memastikan saya memiliki proses yang berjalan (koneksi aktif) terhadap database itu ketika skrip dibuat.
Gilbert
16

Menurut dokumentasi ALTER DATABASE SET , masih ada kemungkinan bahwa setelah mengatur basis data ke mode SINGLE_USER Anda tidak akan dapat mengakses basis data itu:

Sebelum Anda mengatur basis data ke SINGLE_USER, verifikasi opsi AUTO_UPDATE_STATISTICS_ASYNC disetel ke OFF. Ketika diatur ke ON, utas latar belakang yang digunakan untuk memperbarui statistik membutuhkan koneksi terhadap basis data, dan Anda tidak akan dapat mengakses basis data dalam mode pengguna tunggal.

Jadi, skrip lengkap untuk menjatuhkan database dengan koneksi yang ada mungkin terlihat seperti ini:

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

Saya tahu ini sudah terlambat tetapi mungkin ini membantu seseorang. untuk menggunakan ini, buat database Anda offline

ALTER DATABASE dbname SET OFFLINE
Abhishek Upadhyay
sumber
komentar: setelah "drop offline database", file Mdf tidak jatuh! stackoverflow.com/questions/33154141/…
bob217
2

Saya mencoba apa yang dikatakan hgmnz di SQL Server 2012.

Manajemen dibuat untuk saya:

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
sumber
4
Ini tidak akan menutup koneksi yang aktif.
Jens
Pastikan Anda mencentang "Tutup koneksi yang ada"; Jika Anda don ROLLBACK IMMEDIATEpernyataan itu akan dimasukkan. Itu sp_delete_database_backuphistoryberasal dari memeriksa "Hapus cadangan dan pulihkan informasi riwayat untuk basis data".
Christian.K
Memeriksa "Tutup koneksi yang ada" tidak menghasilkan ALTER DATABASE SET SINGLE_USER ...jika tidak ada koneksi saat ini untuk menutup.
ahwm
-1

coba kode C # ini untuk menjatuhkan basis data Anda

DropDatabases public static batal (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
sumber