Case в SQL, как вернуть несколько переменных?
Я хотел бы вернуть несколько значений в мой оператор case, например:
SELECT
CASE
WHEN <condition 1> THEN <value1=a1, value2=b1>
WHEN <condition 2> THEN <value1=a2, value2=b2>
ELSE <value1=a3, value3=b3>
END
FROM <table>
Конечно, я могу написать условие случая несколько раз, каждый раз возвращать одно значение. Однако, поскольку у меня есть много условий, нужно подходить, скажем 100. Нехорошо повторять условие случая снова и снова.
Еще один вопрос, который я хотел бы задать, что произойдет, если одна запись соответствует нескольким условиям? означает ли это, что он вернет все или только последний? например условие 1 может стать подмножеством условия 2. что произойдет?
Ответы
Ответ 1
Основным способом, к сожалению, является повторение.
SELECT
CASE WHEN <condition 1> THEN <a1> WHEN <condition 2> THEN <a2> ELSE <a3> END,
CASE WHEN <condition 1> THEN <b1> WHEN <condition 2> THEN <b2> ELSE <b3> END
FROM
<table>
К счастью, большинство РСУБД достаточно умны, чтобы НЕ нужно было оценивать условия несколько раз. Это просто избыточная типизация.
В MS SQL Server (2005+) вы можете использовать CROSS APPLY в качестве альтернативы этому. Хотя я понятия не имею, насколько он эффективен...
SELECT
*
FROM
<table>
CROSS APPLY
(
SELECT a1, b1 WHERE <condition 1>
UNION ALL
SELECT a2, b2 WHERE <condition 2>
UNION ALL
SELECT a3, b3 WHERE <condition 3>
)
AS case_proxy
Заметным недостатком здесь является то, что эквивалент ELSE отсутствует, и поскольку все условия могут возвращать значения, их необходимо создать так, чтобы только один мог когда-либо быть истинным за раз.
ИЗМЕНИТЬ
Если ответ Yuck изменен на UNION, а не на подход JOIN, он становится очень похожим на это. Основное различие, однако, состоит в том, что это только сканирует входные данные один раз, а не один раз за условие (100 раз в вашем случае).
ИЗМЕНИТЬ
Я также заметил, что вы можете иметь в виду, что значения, возвращаемые оператором CASE, являются фиксированными. Все записи, которые соответствуют одному и тому же условию, получают точные значения sames в value1 и value2. Это можно было бы сформировать так...
WITH
checked_data AS
(
SELECT
CASE WHEN <condition1> THEN 1
WHEN <condition2> THEN 2
WHEN <condition3> THEN 3
...
ELSE 100
END AS condition_id,
*
FROM
<table>
)
,
results (condition_id, value1, value2) AS
(
SELECT 1, a1, b1
UNION ALL
SELECT 2, a2, b2
UNION ALL
SELECT 3, a3, b3
UNION ALL
...
SELECT 100, a100, b100
)
SELECT
*
FROM
checked_data
INNER JOIN
results
ON results.condition_id = checked_data.condition_id
Ответ 2
Оператор A CASE
может возвращать только одно значение.
Возможно, вы сможете превратить это в подзапрос, а затем JOIN
к любым другим отношениям, с которыми вы работаете. Например (с использованием SQL Server 2K5 + CTE):
WITH C1 AS (
SELECT a1 AS value1, b1 AS value2
FROM table
WHERE condition1
), C2 AS (
SELECT a2 AS value1, b2 AS value2
FROM table
WHERE condition2
), C3 AS (
SELECT a3 AS value1, b3 AS value2
FROM table
WHERE condition3
)
SELECT value1, value2
FROM -- some table, joining C1, C2, C3 CTEs to get the cased values
;
Ответ 3
CASE
по определению возвращает только одно значение. Когда-нибудь.
Это также (почти всегда) короткое замыкание, что означает, что если ваше первое условие выполнено, никакие другие проверки не выполняются.
Ответ 4
В вашем случае вы будете использовать два случая, один для каждого значения, которое вы хотите вернуть.
Ответ 5
Вы можете использовать подзаголовок в сочетании с UNION.
Всякий раз, когда вы можете возвращать одни и те же поля для более чем одного условия, используйте OR с круглой скобкой, как в этом примере:
SELECT * FROM
(SELECT val1, val2 FROM table1 WHERE (condition1 is true)
OR (condition2 is true))
UNION
SELECT * FROM
(SELECT val5, val6 FROM table7 WHERE (condition9 is true)
OR (condition4 is true))
Ответ 6
В предложении SQL CASE применяется первое успешно согласованное условие, и любые последующие условия сопоставления игнорируются.
Ответ 7
Вы можете вернуть несколько значений внутри типа данных xml в выражении "case", а затем извлечь их, также доступен блок "else"
SELECT
xmlcol.value('(value1)[1]', 'NVARCHAR(MAX)') AS value1,
xmlcol.value('(value2)[1]', 'NVARCHAR(MAX)') AS value2
FROM
(SELECT CASE
WHEN <condition 1> THEN
CAST((SELECT a1 AS value1, b1 AS value2 FOR XML PATH('')) AS XML)
WHEN <condition 2> THEN
CAST((SELECT a2 AS value1, b2 AS value2 FOR XML PATH('')) AS XML)
ELSE
CAST((SELECT a3 AS value1, b3 AS value2 FOR XML PATH('')) AS XML)
END AS xmlcol
FROM <table>) AS tmp