Làm cách nào để tôi chỉ định các kết nối hiện có, chặt chẽ trong tập lệnh sql


153

Tôi đang thực hiện phát triển tích cực trên lược đồ của mình trong SQL Server 2008 và thường xuyên muốn chạy lại tập lệnh cơ sở dữ liệu thả / tạo của tôi. Khi tôi chạy

USE [master]
GO

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

Tôi thường gặp lỗi này

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

Nếu bạn nhấp chuột phải vào cơ sở dữ liệu trong ngăn thám hiểm đối tượng và chọn tác vụ Xóa từ menu ngữ cảnh, có một hộp kiểm để "đóng các kết nối hiện có"

Có cách nào để chỉ định tùy chọn này trong kịch bản của tôi không?

Câu trả lời:


247

Bạn có thể ngắt kết nối mọi người và quay lại giao dịch của họ với:

alter database [MyDatbase] set single_user with rollback immediate

Sau đó, bạn có thể bỏ cơ sở dữ liệu một cách an toàn :)


8
Tôi đã sử dụng điều này nhưng thường tự hỏi liệu có một cửa sổ cơ hội cho một người dùng khác tham gia với tư cách là "người dùng đơn lẻ" - điều đó có thể không? Thay thế có thể là ALTER DATABASE [MyDatabaseName] SET OFFLINE VỚI ROLLBACK NGAY LẬP TỨC
Kristen

9
Người dùng trong single_user là bạn; trừ khi bạn ngắt kết nối sau khi cài đặt chế độ người dùng. Sau đó, một (1) người dùng khác có thể đăng nhập.
Andomar

Khi bạn đã hủy cơ sở dữ liệu, nếu bạn tạo một cơ sở dữ liệu mới có cùng tên tôi cho rằng nó sẽ ở chế độ multi_user? Vì vậy, bạn không phải chạy: thay đổi cơ sở dữ liệu [MyDatbase] đặt multi_user
AndyM

@AndyM: Vâng, multi_user có lẽ là mặc định
Andomar

2
@Kristen Sử dụng phương pháp của bạn Tôi thấy máy chủ sql không xóa các tệp mdf và ldf. Đặt single_user hoạt động tốt với tôi (Tôi cần liên tục tạo lại db).
2xMax

36

Đi đến studio quản lý và làm mọi thứ bạn mô tả, chỉ thay vì nhấp vào OK, nhấp vào Script. Nó sẽ hiển thị mã nó sẽ chạy mà sau đó bạn có thể kết hợp trong các tập lệnh của mình.

Trong trường hợp này, bạn muốn:

ALTER DATABASE [MyDatabase] SET SINGLE_USER WITH ROLLBACK IMMEDIATE
GO

1
Tôi sẽ cố gắng trả lời câu hỏi này bằng cách thực hiện chính xác những gì bạn mô tả (kịch bản hộp thoại "xóa cơ sở dữ liệu") nhưng nó không thêm dòng ALTER DATABASE vào tập lệnh nếu bạn chọn hộp kiểm "đóng kết nối hiện có".
Matt Hamilton

Tập lệnh tạo từ trình hướng dẫn bao gồm dòng 'cơ sở dữ liệu thay đổi' cho tôi.
nick

Kỳ dị. Phiên bản Management Studio nào? Tôi đang trên 2008 x64.
Matt Hamilton

Tôi cũng vậy: Microsoft SQL Server Management Studio 10.0.1600.22 Hệ điều hành 6.0.6001
nick

8
Có vấn đề tương tự với ALTER DATABASE không được thêm vào tập lệnh. Để tôi thêm nó vào tập lệnh, tôi phải đảm bảo rằng tôi đã có một quá trình đang chạy (kết nối hoạt động) đối với cơ sở dữ liệu đó khi tập lệnh được tạo.
Gilbert

16

Theo tài liệu ALTER DATABASE SET , vẫn có khả năng sau khi đặt cơ sở dữ liệu sang chế độ SINGLE_USER, bạn sẽ không thể truy cập cơ sở dữ liệu đó:

Trước khi bạn đặt cơ sở dữ liệu thành SINGLE_USER, hãy xác minh tùy chọn AUTO_UPDATE_STATISTICS_ASYNC được đặt thành TẮT. Khi được đặt thành BẬT, luồng nền được sử dụng để cập nhật thống kê sẽ có kết nối với cơ sở dữ liệu và bạn sẽ không thể truy cập cơ sở dữ liệu ở chế độ một người dùng.

Vì vậy, một tập lệnh hoàn chỉnh để loại bỏ cơ sở dữ liệu với các kết nối hiện có có thể trông như thế này:

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

Tôi biết rằng đã quá muộn nhưng có thể nó sẽ giúp được ai đó. khi sử dụng, hãy lấy cơ sở dữ liệu của bạn ngoại tuyến

ALTER DATABASE dbname SET OFFLINE

nhận xét: sau khi "thả cơ sở dữ liệu ngoại tuyến", tệp Mdf không bị hủy! stackoverflow.com/questions/33154141/ từ
bob217

2

Tôi đã thử những gì hgmnz nói trên SQL Server 2012.

Quản lý được tạo ra cho tôi:

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
Điều này sẽ không đóng các kết nối hoạt động.
Jens

Đảm bảo bạn đã chọn "Đóng kết nối hiện có"; Nếu bạn không ROLLBACK IMMEDIATEtuyên bố sẽ được bao gồm. Xuất sp_delete_database_backuphistoryphát từ việc kiểm tra "Xóa thông tin lịch sử sao lưu và khôi phục cho cơ sở dữ liệu".
Christian.K

Kiểm tra "Đóng kết nối hiện tại" sẽ không tạo ra ALTER DATABASE SET SINGLE_USER ...nếu không có kết nối hiện tại để đóng.
ahwm

-1

thử mã C # này để hủy cơ sở dữ liệu của bạn

void static void DropDatabase (chuỗi 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();
            }
        }
    }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.