Đặt một ASSERT trong truy vấn SQL Server


7

Là một phần của MERGEtruy vấn mà tôi muốn chạy, tôi muốn xác nhận trong thời gian chạy mà một điều kiện nhất định giữ. Khi MERGEtìm thấy một -match tôi muốn cập nhật một cột nhất định và thực hiện logic sau:

  1. Nếu cột mục tiêu là NULL, hãy viết giá trị nguồn
  2. Nếu mục tiêu là NOT NULL, khẳng định rằng mục tiêu và nguồn giống hệt nhau

Tôi hy vọng rằng hai giá trị luôn giống nhau trong trường hợp 2 nhưng tôi có thể đã mắc lỗi (có lỗi). Khi điều đó xảy ra, tôi muốn phá vỡ tuyên bố và để ứng dụng của tôi báo cáo lỗi. Đây là một tình trạng lỗi rất hiếm gặp, không phải là điều có thể xảy ra như là một phần của xử lý thông thường.

Vì vậy, tôi đã nghĩ rằng tôi có thể lạm dụng một ngoại lệ chia cho 0 để gây ra sự cố:

MERGE
...
WHEN MATCHED BY TARGET THEN UPDATE SET
  TargetCol = CASE
    WHEN TargetCol IS NULL THEN SourceCol
    WHEN TargetCol = SourceCol THEN SourceCol
    ELSE 0/0 END --crash!

Công việc này sẽ đáng tin cậy? Có một lý do này không nên được thực hiện?


Tôi nghĩ rằng RAISEERRORcó thể là một lựa chọn tốt nếu bạn muốn khẳng định trong một truy vấn.
dùng353gre3

@BinayaRegmi không thể gọi nó là một phần của truy vấn.
usr

Tại sao bạn không muốn sử dụng nó trong một khối?
dùng353gre3

1
Bạn đã thử đặt một CHECKràng buộc trên OUTPUTbảng mục tiêu ? Điều đó sẽ làm nổ tung tuyên bố.
Jon Seigel

1
@JonSeigel Tôi đã đề cập đến hàng tá lỗi hợp nhất đã được tìm thấy: mssqltips.com/sqlservertip/3074/ Kẻ Có những vấn đề tham nhũng khó chịu trong số đó.
usr

Câu trả lời:


3

Công việc này sẽ đáng tin cậy?

Câu trả lời cho điều này phụ thuộc vào sức mạnh của sự đảm bảo bạn cần. Đã có những lỗi trong quá khứ xung quanh CASEthứ tự đánh giá, ví dụ, liên tục gấp một biểu thức tạo lỗi . Không có lỗi hiện tại trong SQL Server 2014 mà tôi biết rằng điều đó sẽ ảnh hưởng đến truy vấn của bạn, nhưng điều đó không có nghĩa là chúng có thể không xảy ra trong tương lai.

Đây là một rủi ro với bất kỳ mã nào, nhưng đánh giá của tôi là rủi ro cao hơn khi kết hợp kỹ thuật này với MERGE. Hợp nhất có một triển khai phức tạp và đã có nhiều lỗi liên quan trong quá khứ, như bạn đã biết.

Có một lý do này không nên được thực hiện?

Cá nhân, tôi sẽ tìm cách tránh chia cho 0 như một phần của giải pháp. Một tùy chọn tốt hơn có thể là cố gắng viết một giá trị vi phạm ràng buộc rõ ràng CHECK(hoặc một số khác) trên bảng đích. Điều này sẽ dẫn đến một toán tử Assert rõ ràng trong kế hoạch thực hiện, được định vị sau toán tử Hợp nhất. Có thể không mong muốn thêm một ràng buộc như vậy (hoặc thậm chí có thể nếu cột được phép giữ tất cả các giá trị trong miền loại của nó) nhưng đó là một điều cần xem xét.

Một đề xuất chung khác: tránh cập nhật cột mục tiêu khi các giá trị khớp. Đây là một cách hợp lý, nhưng không phải lúc nào cũng dịch.

DECLARE @target AS TABLE (pk integer PRIMARY KEY, col2 integer NULL CHECK (col2 <> -1));
DECLARE @source AS TABLE (pk integer PRIMARY KEY, col2 integer NULL);

INSERT @target VALUES (1, 100), (2, NULL), (3, 300);
INSERT @source VALUES (1, 100), (2, 200), (3, 301);

MERGE @target AS T
USING @source AS S
    ON S.pk = T.pk
WHEN MATCHED 
    AND
    (
        -- No update if values match
        T.col2 IS NULL 
        OR T.col2 <> S.col2
    )
    THEN UPDATE SET col2 = 
        CASE 
            WHEN T.col2 IS NULL THEN S.col2
            ELSE -1 -- violates CHECK constraint
        END;

Hợp nhất kế hoạch với Assert


1
Điều hay ho của chiến thuật KIỂM TRA là nó được đảm bảo hoạt động. Tôi sẽ lấy đi ý tưởng này để phát triển trong tương lai. Hiện tại tôi quan tâm nhiều hơn đến việc có một cách cực kỳ nhẹ nhàng để khẳng định điều gì đó (nhẹ theo quan điểm phát triển). Đọc phân tích của bạn Tôi nghĩ rằng thủ thuật phân chia là ổn đối với chức năng không quan trọng, không giết người khi thất bại.
usr
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.