Tham gia phải vs Tham gia trái - Tham gia của tôi bị hỏng và tôi không hiểu tại sao


7

http://sqlfiddle.com/#!3/ef71e/1

Tôi quyết liệt cắt giảm câu đố, nhưng tôi nghĩ ý định đó đã tỏa sáng. [Def]là một [DefaultClassification]bảng và [Cls]là một [Classification]bảng có một số bản ghi cũ cần được thêm vào. Bảng DefaultClassification sẽ được sử dụng trong tương lai để sinh ra các nhóm bản ghi mới vào một bảng khác và chúng tôi đang "phá vỡ" một bit hiện có logic / dữ liệu với quá trình này.

Tôi đã làm hết sức mình để chắt lọc toàn bộ những thứ cần thiết nhất, nhưng tôi đã có một quy trình tương tự khác chạy ngay sau quy trình này, vì vậy tôi đang tìm hiểu các thực tiễn tốt nhất tại sao truy vấn này bị hỏng.

Khi tôi viết bài này, tôi dự định nó sẽ chạy trong môi trường 2008+, được viết theo kịch bản hoặc thủ công trong SSMS. Tôi không biết rằng nó sẽ không được viết kịch bản, nhưng nó có thể. Ngay bây giờ nó hoàn toàn chạy bằng tay. Việc khôi phục và chọn ở trên cùng phía trên các thông báo in ở cuối là vì nó không hoạt động đúng, vì vậy điều này cho phép tôi xác thực nó trước khi cam kết. Tuy nhiên, tôi thích một kịch bản hợp lệ mà tôi không phải làm quen với

Vấn đề cụ thể tôi có là ở dòng 62 của bản sửa đổi đó một liên kết http://sqlfiddle.com/#!3/ef71e/1 và nó trông như thế này:

RIGHT OUTER THAM GIA [Def] tcd

nếu tôi lật QUYỀN đó thành TRÁI, nó thực hiện thao tác chèn nhưng không phát hiện các bản sao (để tránh chèn) và nếu tôi thực hiện QUYỀN, nó sẽ phát hiện các bản sao nhưng không xử lý các phần chèn thêm.

Tôi đã làm gì? Và tại sao?


Và tôi đã nói rằng việc sử dụng @@ERRORjuju là xấu, nhưng tôi không biết tại sao, vì vậy điểm thưởng (tiền thưởng 100 rep) cho lời giải thích đó.

Câu trả lời:


11

Tại sao @@ ERROR xấu juju?

Trong SQL Server 2005, sử dụng @@ ERROR làm cho cuộc sống khó khăn hơn cần thiết để phát hiện và bẫy lỗi.

1) Bạn phải kiểm tra sau mỗi tuyên bố. Chỉ từ góc độ bảo trì, con chó của tôi kính bảo hộ sẽ không làm gì để bảo vệ bạn. Bạn cũng có thể lập luận rằng tất cả logic sao chép / dán để xử lý lỗi sẽ che khuất mục đích "thực sự" của mã của bạn.

2) @@ LRI quá dễ bay hơi. Trong đoạn mã sau, dòng 2 ném lỗi 8134. Dòng 3 tôi chọn giá trị và 8134 được tiêu thụ. Tại sao? Bởi vì câu lệnh CHỌN không gây ra lỗi. Ngay cả nếu nó có, nó sẽ là một lỗi khác với lỗi không thành công.

DECLARE @ErrorCode int
SELECT 1/0 AS div_zero
SELECT @@error AS [@@error]
SET @errorCode = @@error
SELECT @errorCode AS errorCode

3) Ngay cả khi bạn xử lý tốt @@ LRI với 2 điều trên, thách thức của tôi xung quanh đó là lỗi vẫn "xuất hiện" ít nhất là trong SSMS. Chạy nửa đầu của truy vấn và mặc dù tôi đã xử lý lỗi một cách hợp lý, nó vẫn sẽ quay trở lại với người gọi.

SET NOCOUNT ON

DECLARE @ErrorCode int;
SELECT 1/0 AS div_zero;
SET @errorCode = @@error;
IF @ErrorCode <> 0
BEGIN
    -- I did something here to handle the error
    -- SSMS still reports that the Query completed with errors
    print 'developer electrocuted';
END
GO

Tương phản với

-- error handled *and* query executes successfully
BEGIN TRY
    -- This will report query executed successfully
     SELECT 1/0 AS handled_div_zero;
END TRY
BEGIN CATCH
SELECT
    ERROR_NUMBER()AS error_number --returns the number of the error.
,   ERROR_SEVERITY() AS error_severity --returns the severity.
,   ERROR_STATE()AS error_state  --returns the error state number.
,   ERROR_PROCEDURE() AS error_procedure --returns the name of the stored procedure or trigger where the error occurred.
,   ERROR_LINE() AS error_line --returns the line number inside the routine that caused the error.
,   ERROR_MESSAGE() AS error_message; --returns the complete text of the error message. The text includes the values supplied for any substitutable parameters, such as lengths, object names, or times.
END CATCH

SQL Server 2012 kết thúc những gì năm 2005 đã bắt đầu và cung cấp THROWĐiều này cho phép bạn xử lý lỗi trong CATCHkhối của mình và sau đó thay vì phá vỡ ngăn xếp cuộc gọi của bạn, giờ đây bạn có thể khắc phục lỗi tương tự đó cho người gọi. Mặt khác, bạn được giảm xuống việc phải raiserror mỗi khi bạn cố gắng sửa một mức trong ngăn xếp cuộc gọi.


Trong hầu hết mọi trường hợp tôi thấy mọi người sử dụng lỗi @@, họ đã bỏ qua việc kiểm tra sau mỗi đoạn mã không rõ ràng và người đó tự hỏi tại sao các lỗi không dừng được. Tôi từ chối vượt qua đánh giá mã khi nó có lỗi @@.
HLGEM

2

Ok, tôi đã viết một bài viết về SQL Server Central ở đây có thể giúp bạn với các câu hỏi tham gia bên ngoài trái / phải của bạn. Tuy nhiên nếu bạn đang cố gắng loại bỏ các bản sao trong trường hợp này, tôi nghĩ rằng những gì bạn đang tìm kiếm là KHÔNG HIỆN TẠI.

SELECT 
      tTCD.ClsID
    , tTCD.ParID
    , tTCD.Name
    , tTCD.IsExpense
    , tTCD.CD
FROM @Default tTCD
WHERE NOT EXISTS (
        SELECT 1 FROM [Def] tcd
            WHERE  tcd.ClsID = tTCD.ClsID
            AND tcd.Name = tTCD.Name
            AND tcd.IsExpense = tTCD.IsExpense)
AND tTCD.IsExpense IS NOT NULL

Mã hiện tại của bạn bằng cách sử dụng RIGHT OUTER THAM GIA có mệnh đề WHERE trên bảng TRÁI. Vì bạn đang loại trừ NULL và trên RIGHT OUTER THAM GIA bất cứ lúc nào không có trận đấu, bạn sẽ nhận được NULL trên bảng TRÁI. Sử dụng KHÔNG EXISTS sẽ giúp nhiều hơn. Tuy nhiên, dữ liệu thử nghiệm của bạn không thực sự có bất kỳ sự trùng lặp nào nên rất khó để nói.


Vâng, đó là một cuộc thảo luận chúng tôi đã có trong phòng chat. Chỉ có khoảng một tá bản sao, nhưng tôi không thể có bất kỳ bản sao nào trong số này khi quy trình này được chạy.
jcolebrand

1

Bạn không thể trao đổi tham gia phải và trái. Chúng có nghĩa là hai điều khác nhau. Bạn cũng cần hiểu tác động của việc có một điều kiện ở đâu trên bàn ở bên trái của một liên kết bên phải hoặc bên phải của một liên kết bên trái. Xem liên kết này để hiểu lý do tại sao điều này thay đổi tham gia vào một tham gia bên trong. http://wiki.lessthandot.com/index.php/WHERE_conditions_on_a_LEFT_JOIN

Xem nếu mã này là những gì bạn muốn:

 SELECT 
          tTCD.ClsID
        , tTCD.ParID
        , tTCD.Name
        , tTCD.IsExpense
        , tTCD.CD
   FROM  [Def] tcd
   LEFT OUTER JOIN @Default tTCD
        ON  tcd.ClsID = tTCD.ClsID
        AND tcd.Name = tTCD.Name
        AND tcd.IsExpense = tTCD.IsExpense
        AND tTCD.IsExpense IS NOT NULL

Đối với tương lai nói chung là tốt nhất để chỉ sử dụng tham gia trái.

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.