Чи оцінює оператор SQL Server CASE всі умови або виходить з першого TRUE умови?


44

Чи CASEоцінює оператор SQL Server (конкретно 2008 або 2012 рр.) Всі WHENумови чи він виходить, коли знайде WHENзастереження, яке оцінює як істинне? Якщо вона проходить через увесь набір умов, чи означає це, що остання умова, що оцінює істину, перезаписує те, що зробила перша умова, яка оцінюється як істинна? Наприклад:

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

Результати - "ТАК", хоча останній, коли умова повинна привести його до "НІ". Здається, що він закінчується, як тільки виявляє першу ІСТИНУЮ умову. Чи може хтось підтвердити, якщо це так ?


5
Дуже близько: Чи читає SQL Server всю функцію COALESCE, навіть якщо перший аргумент не NULL? (як COALESCE()перекладається у CASEвираз.)
ypercubeᵀᴹ

Відповіді:


46

• Повертає результат_експресії першої input_expression = When_expression, що оцінює значення TRUE .

Довідка http://msdn.microsoft.com/en-us/library/ms181765.aspx


Це стандартна поведінка SQL:

  • CASEВираз для першого справжнього стану.

  • Якщо немає справжньої умови, вона оцінюється до ELSEчастини.

  • Якщо немає справжньої умови і немає її ELSEчастини, вона оцінюється NULL.


2
Я просто хотів переконатися, що якщо у мене є 3 випадки, які б усі оцінювали як істинні, я хотів би лише виконати завдання першого, який оцінює як істинне, а не другого 2 (навіть якщо вони також оцінювали як істинне ). З прикладу запиту в моїх питаннях, мабуть, це так. Я просто хотів підтвердити. Я також сподівався, що SQL читає умови CASE від Top до Bottom. Дякую!
Хуан Велес

15

SQL Server зазвичай проводить оцінку короткого замикання для операторів 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;  

Однак існує кілька типів тверджень, які за SQL Server 2012 не мають короткого замикання. Дивіться посилання від ypercube в коментарях.

Oracle завжди робить оцінку короткого замикання . Див . Посилання 11.2 на мову SQL . Або порівняйте наступне ( 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;

Цей самий тест неможливо зробити з MySQL, оскільки він повертає NULL для ділення на нуль. ( SQL Fiddle )


Як щодо цього ?: SQL-
Fiddle


@ypercube Це дійсно цікава поведінка. Він оцінює код, який би виконувався в іншій частині, але, схоже, ігнорує його залежно від того, які інші вирази КОЛИ існують та чи ділиться на нуль всередині MIN чи ні. Дивіться sqlfiddle.com/#!6/d41d8/4468
Leigh

@ypercube Тепер, коли я прочитав декілька посилань, які ви опублікували, ви б сказали, що є достатньо крайніх випадків, щоб сказати, що відповідь на те, чи проводить SQL Server коротке замикання, - зазвичай?
Лі Ріффель

3
Так, я погодився б "зазвичай". Як Аарон вказує на свою відповідь, одного тесту достатньо, щоб спростувати "СЛУЧАЙ завжди коротке замикання". Але зазвичай так і є.
ypercubeᵀᴹ

7

Схоже, що MS SQL Server також використовує оцінку короткого замикання.

У наступному тесті у мене є 3 тести. Перший завжди правдивий, другий виходить з ладу без посилання на таблицю, а третій не працює лише тоді, коли дані враховуються.
У цьому конкретному виконанні обидва рядки повертаються успішно. Якщо я коментую перший КОЛИ, або перший і другий, то я отримую невдачі.

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

якщо оператор case, що використовується в WHEREумові, і перший випадок, коли операція включає оцінку значень стовпців з таблиці, а перший рядок таблиці не задовольняє цій умові, оператор case перейде до наступного випадку, коли оператор.

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

У MySQL він вийде із оператора case на першому вірному варіанті. Якщо у вас є можливість декількох істинних значень, ви хочете розмістити бажану відповідь раніше в послідовності.


Питання стосується SQL Server.
Джеймс Андерсон
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.