SQL Server CASE WHEN без использования CASE WHEN

Есть ли способ переписать оператор Transact SQL, который использует структуру CASE WHEN, чтобы сделать то же самое без использования CASE WHEN?

Я использую продукт со встроенным конструктором запросов и собственным псевдо-SQL. У него есть ограничения на то, что я могу использовать с SQL Server и Oracle. Итак, у меня есть этот столбец, который, когда базовой базой данных является Oracle, использует DECODE (который поддерживается). Однако мне нужно заставить его работать с SQL Server, а CASE WHEN не поддерживается.

Заявление, которое я пытаюсь преобразовать, похоже на

Decode (StatusColumn,  'Value 1',
Decode(Sign(Now()-TargetDateColumn)),1,'Past
Due', 'Outstanding'),  'Value 2',
Decode(Sign(Now()-TargetDateColumn)),1,'Past
Due', 'Outstanding'),  'Value 3',
Decode(Sign(Now()-TargetDateColumn)),1,'Past
Due', 'Outstanding'),  'Value 4')

У меня есть ограниченный набор параметров T-SQL для использования, и CASE WHEN не вариант. У меня есть IsNull и Coalesce, но я не уверен, помогут ли они мне с этим.

Не беспокойтесь о расчетах даты, они решены.

Я искал здесь вопросы CASE WHEN, но безрезультатно.

Спасибо!

Обновление:

Я понимаю, что должен был дать более подробную информацию о причине ограничений, так как это ресурс разработчика, и можно было бы предположить, что это продукт разработки. Нет, это не так.

Я использую корпоративный программный продукт со встроенным конструктором запросов и собственным псевдо-SQL. У него есть ограничения на то, что я могу использовать с SQL Server и Oracle. По сути, все, что не нарушает синтаксический анализ встроенного механизма запросов, является игрой. Это означает все санкционированные функции и выражения, плюс все абстракции данных (внутренние объекты, соответствующие физической таблице в базе данных, и другие запросы, созданные с помощью продукта), плюс все из Oracle SQL или Transact SQL, которые явно не нарушают синтаксический анализ. .

Причина, по которой CASE WHEN у меня не работает, заключается в том, что он нарушает синтаксический анализ псевдо-SQL механизмом запросов.

В конечном счете, я хотел бы попробовать:

  1. Используйте только конструктор запросов продукта SQL, который проходит синтаксический анализ ИЛИ
  2. Используйте несколько дополнительных ресурсов из базы данных SQL Server и конструктора запросов, чтобы сделать это.

Основываясь на нескольких хороших ответах, которые я получил, вот подход, который до сих пор работал для меня.

Джейсон ДеФонтес предложил мне использовать представление базы данных для выполнения правил CASE WHEN, и это относится к пункту 2 выше. Это работает для меня, потому что представление достаточно динамично, и мне не нужно его обслуживать (в отличие от подхода к таблицам истинности Richartallent, который, я считаю, близок к подходу Джейсона). Предложение Паскаля о создании функции будет идти в том же направлении, но, вероятно, нарушит синтаксический анализ.

Итак, я создал представление базы данных, которое выполняет все преобразования с помощью CASE WHEN, и я добавил его в свой SQL-запрос, соединил его с существующим SQL, и все заработало нормально. Я понимаю, что, вероятно, добавляю нагрузку на механизм базы данных, так как ему придется дважды извлекать один и тот же набор данных (один для представления и один для запроса), но это один из тех случаев, когда это вряд ли проблема.

Учитывая, что этот дизайн «использовать представление для его запутывания» работает для меня, мне интересно, какой подход будет более эффективным:

  • Использование выбора с CASE WHEN;
  • Используя CTE (опять же, Richardtallent);
  • Использование объединения всех (HLGEM);
  • Использование подзапросов (MisterZimbu);

Я все равно проверю предложение Арамиса Уайлера, так как оно, вероятно, может попасть в пункт № 1 выше.

На данный момент ответ Джейсона был принят. Учитывая, что я использовал CASE WHEN в представлении, возможно, заголовок вопроса оказался неудачно выбранным. Я поднял всех, кто предложил что-то, что помогло в этом процессе. Я не знаю, повлияет ли это на твою репутацию или нет, но я подумал, что это хороший поступок.

Еще раз, я хочу поблагодарить вас всех за вашу помощь и попросить вас отредактировать что-либо по вопросу, который вам не подходит (это мой первый вопрос, а английский - мой второй язык).


person ezingano    schedule 05.11.2009    source источник
comment
Мне очень любопытно.. ПОЧЕМУ у вас нет возможности использовать Case When? Ваша компания установила такую ​​политику?!!? Если у вас нет внешних обязательных ограничений, Case When, безусловно, поддерживается на SQL Server.   -  person Charles Bretana    schedule 05.11.2009
comment
Да, но инструмент запросов может не поддерживать его, ограничивая результаты выбора выражениями и вызовами функций.   -  person pascal    schedule 05.11.2009
comment
Это ограничение продукта, над которым мы работаем. Как я уже упоминал, в продукте есть конструктор запросов и механизм запросов, а также собственный SQL, который как бы «транслирует»/«адекватно» использует либо Oracle, либо SQL Server. Я подозреваю, что декодирование поддерживается, потому что это функция, сказали ли мне, что Case-When - это не функция, а скорее выражение. Я думаю, что Case-When нарушит синтаксический анализ механизма запросов из-за определений псевдо-SQL.   -  person ezingano    schedule 05.11.2009
comment
Не зная точно, каковы возможности вашего стороннего генератора запросов, я не верю, что на вашу проблему можно ответить. Если вы укажете, какой сторонний инструмент вы используете, возможно, кто-то, имеющий опыт работы с этим продуктом, сможет вам помочь.   -  person Charles Bretana    schedule 05.11.2009
comment
Я хотел проверить, есть ли способ использовать что-то вроде подзапросов или Union или их комбинации. Спасибо за помощь.   -  person ezingano    schedule 05.11.2009
comment
Как называется продукт? Я хотел бы учитывать это отсутствие функциональности при любом решении об использовании.   -  person JeffO    schedule 05.11.2009
comment
@GuinnessFan: Я понимаю ваш комментарий, но я скажу вам следующее: это не продукт разработки, а скорее корпоративное программное обеспечение, которое выполняет очень специфические задачи и делает это очень хорошо. Тот факт, что он имеет встроенный дизайнер запросов, каким бы ограниченным он ни был (и, ИМХО, он не так уж ограничен), является плюсом, а не недостатком функциональности. Итак, учитывая, что это не продукт разработки, я не думаю, что это будет иметь значение для вас или кого-либо еще при принятии этого конкретного решения.   -  person ezingano    schedule 06.11.2009
comment
Люди, я получил здесь хорошие ответы, и один из них сработал. Я отредактирую вопрос, пытаясь предоставить больше информации. Я поднял всех, кто сделал предложение (в конце концов, все они помогли мне с моим подходом), и сейчас я выбираю ответ Джейсона ДеФонтеса. Если у вас есть соображения по поводу производительности или более элегантных подходов, поделитесь ими. Еще раз спасибо всем, кто вложил в это 2 цента.   -  person ezingano    schedule 06.11.2009


Ответы (6)


Можете ли вы переместить логику CASE/WHEN в представление, а затем заставить инструмент запрашивать представление?

person Jason DeFontes    schedule 05.11.2009
comment
Знаешь что? Может быть, я смогу! Я заканчиваю некоторые другие задачи, но начну пробовать предложения как можно скорее. Пока кажется, что это он. Дизайнер запросов ограничен, но я могу передать несколько вещей (но не CASE-WHEN, это нарушает синтаксический анализ). Я действительно могу попробовать этот подход. - person ezingano; 06.11.2009

У вас есть союз все в наличии? Возможно, вы могли бы написать запрос для каждого из условий с условием case в предложении where и объединить их вместе.

person HLGEM    schedule 05.11.2009
comment
+1 Отличная идея (ну кроме прожига инструмента псевдо-SQL) - person Andomar; 05.11.2009
comment
Я попробую. Я предполагаю, что ваш ответ - это то, к чему я стремился: какой-то способ справиться с этим, используя базовый SQL вместо функции. Я оставлю вопрос без ответа еще немного, чтобы посмотреть, можно ли предложить что-то еще. Если нет, то я приму ваш ответ. Спасибо. - person ezingano; 05.11.2009
comment
Я проголосовал за это, но у UNION есть два недостатка: (1) многократные обращения к колодцу (MSSQL не собирается это хорошо оптимизировать) и (2) дублированный код. Частично это можно смягчить, переместив общие части в CTE, но если вы пытаетесь избежать CASE, CTE еще больше зависит от платформы. - person richardtallent; 05.11.2009
comment
Ричард, я согласен, но иногда вы застряли с ограничениями инструмента, который вам необходимо использовать. Union all будет лучше для производительности, чем union (поскольку мы знаем, что разные запросы не будут иметь общих значений), но он может быть или не быть доступным. - person HLGEM; 05.11.2009
comment
@richardtallent: я не знаю, смогу ли я использовать его прямо в нашем конструкторе / движке запросов, но я собираюсь попробовать другой подход, вдохновленный предложением Джейсона ДеФонтеса. - person ezingano; 06.11.2009

Можете ли вы написать собственные подзапросы? Вероятно, нет, если у вас даже нет доступа к CASE WHEN, но это, вероятно, тоже сработает:

select
    ...,
    coalesce(c1.value, c2.value, c3.value, ..., <default value>)
from MyTable
left join (select <result 1> as value) c1 on <first condition>
left join (select <result 2> as value) c2 on <second condition>
left join (select <result 3> as value) c3 on <third condition>
person MisterZimbu    schedule 05.11.2009
comment
Я также попробую это, так как это может быть натяжкой для ограничений механизма запросов, но это очень просто для понимания и ближе к тому, что я пытаюсь сделать. Спасибо! - person ezingano; 05.11.2009

Напишите функцию, которая выполняет вычисления, используя CASE WHEN.

person pascal    schedule 05.11.2009
comment
Я не могу, пока. Я хотел бы попытаться решить эту проблему, если это возможно, используя то, что у меня есть в конструкторе/движке запросов. Я много думал, прежде чем задать вопрос, потому что знал, что он, вероятно, привлечет больше внимания к ограничениям, чем к самому вопросу. В конце концов, я подумал, что это может быть полезно кому-то еще в той же ситуации. Или хотя бы пища для размышлений об эффективности аналогичных оценок. - person ezingano; 05.11.2009

Это уродливо и в зависимости от количества значений, которые у вас есть, может быть нежизнеспособным. Но, строго говоря, я думаю, что что-то вроде этого будет работать как перевод из приведенного выше сегмента запроса:

выберите «PastDue» из имени таблицы, где Now() > TargetDateColumn и (StatusColumn = «Value 1» или StatusColumn = «Value 2» или StatusColumn = 'Value 3') union выберите 'Outstanding', где Now() ‹ TargetDateColumn и (StatusColumn = 'Value 1' или StatusColumn = 'Value 2' или StatusColumn = 'Value 3') union выберите 'Value 4', где НЕ (StatusColumn = 'Значение 1' или StatusColumn = 'Значение 2' или StatusColumn = 'Значение 3')

person Aramis wyler    schedule 05.11.2009

Я не совсем уверен, что понимаю ваш код, но это должно дать вам представление о другом подходе.

Сначала создайте таблицу:

CREATE TABLE StatusLookup(
   value nvarchar(255),
   datesign shortint,
   result varchar(255));

Теперь заполните его таблицей истинности (по-видимому, здесь много повторяющейся логики, возможно, это должны быть две таблицы истинности с перекрестным соединением между ними):

INSERT INTO StatusLookup(value, datesign, result) VALUES ('Value 1', -1, 'Outstanding')
INSERT INTO StatusLookup(value, datesign, result) VALUES ('Value 1', 0, 'Outstanding')
INSERT INTO StatusLookup(value, datesign, result) VALUES ('Value 1', 1, 'Past Due')
INSERT INTO StatusLookup(value, datesign, result) VALUES ('Value 2', -1, 'Outstanding')
INSERT INTO StatusLookup(value, datesign, result) VALUES ('Value 2', 0, 'Outstanding')
INSERT INTO StatusLookup(value, datesign, result) VALUES ('Value 2', 1, 'Past Due')
INSERT INTO StatusLookup(value, datesign, result) VALUES ('Value 3', -1, 'Outstanding')
INSERT INTO StatusLookup(value, datesign, result) VALUES ('Value 3', 0, 'Outstanding')
INSERT INTO StatusLookup(value, datesign, result) VALUES ('Value 3', 1, 'Past Due')

Наконец, присоединяйтесь и предоставьте ответ по умолчанию:

SELECT mytable.*, COALESCE(statuslookup.result, 'Value 4')
FROM
    mytable LEFT JOIN statuslookup ON
        statuslookup.value = StatusColumn
        AND statuslookup.datesign = Sign(Now()-TargetDateColumn)

Одно из ключевых преимуществ этого подхода заключается в том, что он помещает бизнес-логику в таблицы данных, а не в код, который часто более удобен в сопровождении и расширяем.

person richardtallent    schedule 05.11.2009
comment
Ваше предложение, вероятно, сработает, так как я могу использовать COALESCE из механизма запросов. Я неравнодушен к таблице истинности, так как не хотел бы ею управлять (не то чтобы это была плохая идея, потому что я уже использовал ее раньше, но она добавляет дополнительный уровень управления, который не сработал бы для меня в данном случае). конкретный сценарий), но это можно было бы сделать. Спасибо. - person ezingano; 06.11.2009