Có cách nào để kiểm tra xem DELETE sẽ thất bại do các ràng buộc không?


10

Tôi muốn có thể dự đoán liệu XÓA có bị vi phạm ràng buộc hay không mà không thực sự xóa.

Lựa chọn của tôi để làm điều này là gì? Có cách nào đơn giản để thực hiện "chạy khô" XÓA không?


Bạn đang cố gắng ngăn chặn ngoại lệ cho tuyên bố này một mình hay bạn đang cố gắng giảm bớt xử lý lỗi trong một lô lớn hơn có chứa phần xóa này?
Aaron Bertrand

3
Bạn có thể kiểm tra xem FK có tồn tại không và chạy câu lệnh CHỌN để kiểm tra các giá trị?
SQLRockstar

Aaron: Chúng tôi cần chạy một loạt nhiều XÓA trong các giao dịch riêng biệt. Nếu một thất bại, những người khác đã cam kết. .
Jay Sullivan

Vẫn không chắc là tôi hiểu. Bạn đang cố gắng để phần còn lại của việc xóa thành công hay bạn đang cố gắng kiểm tra trước xem tất cả các lần xóa sẽ thành công hay không ai trong số họ xóa?
Aaron Bertrand

Aaron: Xin lỗi tôi đã không nói rõ, nhưng đúng vậy, tôi đang cố gắng đảm bảo tất cả họ đều thành công, hoặc không ai trong số họ thành công.
Jay Sullivan

Câu trả lời:


24

Nếu mục tiêu của bạn là xử lý tất cả các lần xóa chỉ khi tất cả chúng thành công, tại sao không sử dụng TRY / CATCH:

BEGIN TRANSACTION;
BEGIN TRY
  DELETE #1;
  DELETE #2;
  DELETE #3;
  COMMIT TRANSACTION;
END TRY
BEGIN CATCH
  ROLLBACK TRANSACTION;
END CATCH

Nếu mục tiêu là cho phép tất cả các lần xóa thành công thành công ngay cả khi một hoặc nhiều lần sẽ thất bại, thì bạn có thể sử dụng TRY / CATCH riêng lẻ, ví dụ:

BEGIN TRY
  DELETE #1;
END TRY
BEGIN CATCH
  PRINT 1;
END CATCH

BEGIN TRY
  DELETE #2;
END TRY
BEGIN CATCH
  PRINT 1;
END CATCH

6

Một tùy chọn là bắt đầu một giao dịch, chạy xóa của bạn và sau đó luôn quay lại:

begin tran

delete Table1 where col1 = 1

-- Test whether it is there
select * from Table1 where col1 = 1

rollback tran

-- Confirm that it is still there
select * from Table1 where col1 = 1

1
Và nếu xóa thành công, chạy lại? Nếu xóa rất tốn kém thì sao? Và nếu xóa thất bại thì sao? Bạn đã thực hiện một xóa và hai lựa chọn. Làm thế nào để tôi quyết định di chuyển vào lần xóa tiếp theo hay không?
Aaron Bertrand

1
Nếu đó là một phần của các yêu cầu, thì chúng nên được xử lý. Câu trả lời này liên quan đến "chạy đơn giản".
GaTechThomas

Vâng, họ không biết khi bạn gửi câu trả lời đầu tiên, nhưng giờ họ đã được làm rõ.
Aaron Bertrand

4
@GaTechThomas Aaron đóng góp rất nhiều, vì vậy đôi khi anh ấy ngắn gọn, nhưng tôi chắc chắn ý định của anh ấy không phải là để gây hấn. Tôi đã thảo luận điều này trong The Heap và tôi cũng rất biết ơn về cơ hội được làm điều đó với bạn.
Jack nói hãy thử topanswers.xyz

1
@JackDoureb Tôi đã đọc các bình luận của Heap mà bạn tham khảo và hiểu quan điểm. Các ý kiến ​​cộng đồng là hợp lý, ngoại trừ phần mà tôi được gọi là một chú hề vì đã chỉ ra sự hung hăng của anh ta. Tôi không hiểu làm thế nào tôi là người được coi là hung hăng. Tôi đã đăng một câu trả lời hợp pháp cho câu hỏi vì nó được đặt ra vào thời điểm đó. Nó không yêu cầu chất lượng sản xuất - đôi khi bạn chỉ cần nhanh chóng và dễ dàng. Vì vậy, trên tôi câu trả lời tôi nhận được câu hỏi nhọn. Ngoại hình là anh ta đang chê bai câu trả lời của tôi để anh ta được chọn. Chúng ta có nên lấy chủ đề này ở nơi khác?
GaTechThomas

0

Tôi muốn cải thiện giải pháp do Aaron Bertrand cung cấp với một số mã, trong trường hợp bạn muốn thử thêm bất kỳ phần tử nào của bảng, quản lý các ngoại lệ để bỏ qua thất bại hoặc cũng dừng các lỗi xử lý sau.

Cái này sẽ chọn các bản ghi từ bảng và sau đó cố gắng xóa chúng mà không có ngoại lệ:

DECLARE @MaxErrors INT
SET @MaxErrors = 5;    // Setting 0 will stop process after the first error!

SELECT
    [Id]
    , ROW_NUMBER() OVER (ORDER BY Id ASC) AS [Index]
INTO #DeletingItems
FROM myTable

DECLARE @Current INT, @Max INT, @Id INT, @TotErrors INT
SELECT
    @Current = 1
    , @TotErrors = 0
    , @Max = MAX([Index])
FROM #DeletingTable

WHILE @Current <= @Max
BEGIN
    SELECT
        @Id = [Id]
    FROM #DeletingItems
    WHERE
        [Index] = @Index;

    BEGIN TRANSACTION;    
    BEGIN TRY    
        DELETE FROM myTable WHERE [Id] = @Id;

        COMMIT TRANSACTION;    
    END TRY    
    BEGIN CATCH    
        ROLLBACK TRANSACTION;

        SET @TotErrors = @TotErrors + 1;

        IF @TotErrors > @MaxErrors
            BREAK;
    END CATCH

    SET @Current = @Current + 1;
END

1
Tại sao? Làm thế nào đây là một cải tiến so với câu trả lời được chấp nhận?
ToolmakerSteve
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.