#sql #database #case
#sql #База данных #случай
Вопрос:
Учитывая выражение SQL CASE с вложенными выражениями CASE, я ищу лучший способ эмулировать прерывание C или Python в выражении вложенного CASE, чтобы я мог оценить остальные варианты outer WHEN.
Например, представьте
select CASE
WHEN C1 THEN CASE
WHEN CA THEN 100
WHEN CB THEN 200
-- implied ELSE NULL
END
WHEN C2 THEN CASE
WHEN CC THEN 300
WHEN CD THEN 400
ELSE 500
END
WHEN C3 THEN CASE
WHEN CE THEN 600
END
WHEN C4
... etc
предположим, что условия C1 и C3 являются истинными, C2 и C4 являются ложными.
также предположим, что CA и CB являются ложными, CE является истинным.
Внутренний регистр для C1 принимает подразумеваемое значение ELSE NULL. Я хотел бы функционально иметь возможность сказать ELSE BREAK и разрешить вычислять C2, C3 и т.д. Как часть внешнего случая. Желаемый результат равен 600.
Лучший способ, который я нашел, — заменить внешний регистр объединением всех внутренних регистров.
например
COALESCE(
CASE C1 THEN
CASE
WHEN CA THEN 100
WHEN CB THEN 200
END
END
,
CASE C2 THEN
CASE
WHEN CC THEN 300
WHEN CD THEN 400
ELSE 500
END
END
,
CASE C3 THEN
CASE
WHEN CE THEN 600
END
END
,
... etc )
У кого-нибудь есть другие идеи? При нескольких уровнях регистра исходный код увеличивается в размере, что затрудняет его обслуживание.
Я использую стандартный SQL 2008, без расширений, которые можно найти в T / SQL или SQL / PLUS и т.д.
Может быть, у вас есть способ отформатировать мое решение, чтобы сделать его наиболее читаемым?
Спасибо.
Ответ №1:
В sql лучше всего использовать таблицу и объединение, поэтому в вашем примере создайте таблицу поиска, подобную этой (строка столбца предназначена только для того, чтобы я мог ссылаться позже)
Row C1 C2 C3 CA CB CC CD CE Value
1 T F F T F F F F 100
2 T F F F T F F F 200
3 F T F F T F F F 300
4 F T F F F F T F 400
5 F T F T F T F T 500
6 F F T F F F F T 600
....
Тогда ваш оператор sql будет выглядеть следующим образом
SELECT l.[value]
FROM table t
JOIN lookup l ON (t.C1 = l.C1 AND t.C2 = l.C2 AND t.C3 = l.C3)
AND (t.CA = l.CA
OR t.CB = l.CB
OR t.CC = l.CC
OR t.CD = l.CD
OR t.CE = l.CE)
Я считаю, что это логика, которая вам нужна для вашего внутреннего и вашего внешнего.
Обратите внимание на строку 5, поскольку последние 5 указаны в соединении, это позволит подстановке действовать как ELSE в ваших внутренних случаях.
Вы могли бы просто иметь все и в соединении и «полную» таблицу поиска — это может быть проще для отладки и работы.
Комментарии:
1. Я упростил проблему, когда задал исходный вопрос. В реальной проблеме, которую я решаю, значения в предложениях WHEN являются выражениями, которые ссылаются на 1 или более дополнительных столбцов, поэтому соединение со второй таблицей у меня не работает. Я вижу, как предложенный вами шаблон соединения был бы действительно полезен в других ситуациях. Спасибо.
2. @GaryGilbert — Объединения могут включать выражения, этот метод все еще может работать.
Ответ №2:
Один из способов:
select CASE
WHEN C1 AND CA THEN 100
WHEN C1 AND CB THEN 200
--- simulated BREAK
WHEN C2 THEN CASE
WHEN CC THEN 300
WHEN CD THEN 400
ELSE 500
END
WHEN C3 AND CE THEN 600
--- simulated BREAK
WHEN C4
... etc
Комментарии:
1. Иногда работает выравнивание встроенного выражения case только с помощью внешнего регистра. Я думаю, что это может затруднить обслуживание конечного запроса. Комментарии и отступы могут помочь. Проблема, к которой я обращаюсь, имеет около дюжины предложений внешнего регистра WHEN, многие из которых имеют внутренние регистры с 5-8 предложениями WHEN. Сведение его к одному регистру означает, что может быть 60 предложений WHEN, многие из которых повторяют внутренние выражения WHEN. Проблема усугубилась бы, если бы выражение CASE было вложено глубиной более 2. Они радуются декларативному непрограммному языку. 🙂
2. @GaryGilbert: да, для сложных вложенных случаев подход Хогана кажется более подходящим. Я бы тоже использовал это.