Câu lệnh CASE của SQL Server có đánh giá tất cả các điều kiện hoặc thoát khỏi điều kiện TRUE đầu tiên không?


44

CASECâu lệnh SQL Server (2008 hoặc 2012, cụ thể) có đánh giá tất cả các WHENđiều kiện hay nó thoát khi nó tìm thấy một WHENmệnh đề đánh giá là đúng? Nếu nó đi qua toàn bộ các điều kiện, điều đó có nghĩa là điều kiện cuối cùng được đánh giá là đúng sẽ ghi đè lên điều kiện đầu tiên được đánh giá là đúng? Ví dụ:

SELECT
    CASE
        WHEN 1+1 = 2 THEN'YES'
        WHEN 1+1 = 3 THEN 'NO'
        WHEN 1+1 = 2 THEN 'NO' 
    END

Kết quả là "CÓ" mặc dù lần cuối cùng khi điều kiện sẽ làm cho nó đánh giá thành "KHÔNG". Có vẻ như nó thoát khi tìm thấy điều kiện TRUE đầu tiên. Ai đó có thể vui lòng xác nhận nếu đây là trường hợp .


5
Liên quan rất chặt chẽ: SQL Server có đọc tất cả hàm COALESCE ngay cả khi đối số đầu tiên không phải là NULL không? (như COALESCE()được dịch thành một CASEbiểu thức.)
ypercubeᵀᴹ

Câu trả lời:


46

• Trả về result_expression của input_expression = when_expression đầu tiên ước tính thành TRUE .

Tham khảo http://msdn.microsoft.com/en-us/l Library / ms181765.aspx


Đây là hành vi SQL tiêu chuẩn:

  • Một CASEbiểu thức đánh giá điều kiện đúng đầu tiên.

  • Nếu không có điều kiện thực sự, nó đánh giá ELSEmột phần.

  • Nếu không có điều kiện thực sự và không có ELSEphần, nó đánh giá NULL.


2
Tôi chỉ muốn đảm bảo rằng nếu tôi có 3 điều kiện trường hợp tất cả sẽ đánh giá là đúng, tôi sẽ chỉ muốn nhiệm vụ của cái đầu tiên đánh giá là đúng để thực hiện chứ không phải 2 điều kiện còn lại (mặc dù chúng cũng được đánh giá là đúng ). Từ truy vấn mẫu trong câu hỏi của tôi, điều này dường như là trường hợp. Tôi chỉ muốn xác nhận. Tôi cũng hy vọng rằng SQL đọc các điều kiện CASE từ trên xuống dưới. Cảm ơn!
Juan Velez

15

SQL Server thường thực hiện đánh giá ngắn mạch cho các câu lệnh CASE ( SQLFiddle ):

--Does not fail on the divide by zero.
SELECT 
   CASE 
      WHEN 1/1 = 1 THEN 'Case 1'
      WHEN 2/0 = 1 THEN 'Case 2'
   END;

--Fails on the divide by zero.
SELECT 
   CASE 
      WHEN 1/1 = 99 THEN 'Case 1'
      WHEN 2/0 = 99 THEN 'Case 2'
   END;  

Tuy nhiên, có một số loại câu lệnh mà kể từ SQL Server 2012 không ngắn mạch chính xác. Xem liên kết từ ypercube trong các ý kiến.

Oracle luôn luôn đánh giá ngắn mạch . Xem Tài liệu tham khảo ngôn ngữ SQL 11.2 . Hoặc so sánh như sau ( SQLFiddle ):

--Does not fail on the divide by zero.
SELECT
  CASE 
    WHEN 1/1 = 1 THEN 'Case 1'
    WHEN 2/0 = 1 THEN 'Case 2'
  END
FROM dual;


--Fails on the divide by zero.
SELECT
  CASE 
    WHEN 1/1 = 99 THEN 'Case 1'
    WHEN 2/0 = 99 THEN 'Case 2'
  END
FROM dual;

Thử nghiệm tương tự này không thể được thực hiện với MySQL vì nó trả về NULL cho phép chia cho số không. ( Câu đố SQL )


Làm thế nào về điều này?: SQL-Fiddle
ypercubeᵀᴹ


@ypercube Đó thực sự là một hành vi thú vị. Nó đang đánh giá mã sẽ chạy trong phần khác, nhưng dường như bỏ qua nó tùy thuộc vào biểu thức WHEN nào khác tồn tại và việc chia cho số 0 có nằm trong MIN hay không. Xem sqlfiddle.com/#!6/d41d8/4468
Leigh Riffel

@ypercube Bây giờ tôi đã đọc một số liên kết bạn đã đăng, bạn có nói rằng có đủ các trường hợp cạnh để nói rằng câu trả lời cho việc SQL Server có đánh giá ngắn mạch không - thường là?
Leigh Riffel

3
Có, tôi đồng ý về "thông thường". Khi Aaron chỉ ra câu trả lời của mình, một bài kiểm tra là đủ để từ chối "CASE luôn bị đoản mạch". Nhưng nó thường làm.
ypercubeᵀᴹ

7

Dường như MS SQL Server cũng sử dụng đánh giá ngắn mạch.

Trong bài kiểm tra sau tôi có 3 bài kiểm tra. Cái đầu tiên luôn luôn đúng, cái thứ hai thất bại mà không tham chiếu bảng và cái thứ ba chỉ thất bại khi dữ liệu được tính đến.
Trong lần chạy đặc biệt này, cả hai hàng được trả về thành công. Nếu tôi nhận xét KHI đầu tiên, hoặc lần đầu tiên và lần thứ hai thì tôi nhận được thất bại.

CREATE TABLE casetest (test varchar(10))
GO
INSERT INTO casetest VALUES ('12345'),('abcdef')
GO

SELECT CASE WHEN LEN(test)>1 THEN test
        WHEN 1/0 = 1 THEN 'abc'
        WHEN CAST(test AS int) = 1 THEN 'def'
        END
FROM casetest
GO

1

nếu câu lệnh case được sử dụng trong WHEREđiều kiện và trường hợp đầu tiên khi câu lệnh liên quan đến việc đánh giá các giá trị cột từ bảng và hàng đầu tiên trong bảng không thỏa mãn điều kiện này, câu lệnh case sẽ chuyển sang trường hợp tiếp theo khi câu lệnh.

declare @tbl table(id int)
insert into @tbl values(1)
insert into @tbl values(2)
insert into @tbl values(3)

--Fails on the divide by zero.
SELECT * FROM @tbl
where  CASE 
        WHEN id = 2 THEN 1 -- first row in table will not satisfy the condition
        WHEN 2/0 = 1 THEN 1
        ELSE 0
      END =1

-- when filter the records to only who will staisfy the first case when condition, it 
will not fail on the divide by zero
SELECT * FROM @tbl
where ID=2 and -- first row in table will  satisfy the condition
  CASE 
    WHEN id = 2 THEN 1
    WHEN 2/0 = 1 THEN 1
    ELSE 0
  END =1

1

Trong MySQL, nó sẽ thoát khỏi câu lệnh tình huống trên tùy chọn đúng đầu tiên. Nếu bạn có khả năng có nhiều giá trị thực, bạn muốn đặt câu trả lời ưa thích trước đó trong chuỗi.


Câu hỏi là về SQL Server.
James Anderson
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.