Я написал оператор case с> 100 вариантами, где я использую один и тот же оператор в 4 местах в простом запросе.
Один и тот же запрос дважды с объединением между ними, но также выполняет подсчет, и поэтому в группе также содержится оператор case.
Это делается для того, чтобы переименовать некоторые названия компаний, где разные записи для одной и той же компании пишутся по-разному.
Я пытался объявить переменную как VarChar (MAX)
declare @CaseForAccountConsolidation varchar(max)
SET @CaseForAccountConsolidation = 'CASE
WHEN ac.accountName like ''AIR NEW Z%'' THEN ''AIR NEW ZEALAND''
WHEN ac.accountName LIKE ''AIR BP%'' THEN ''AIR BP''
WHEN ac.accountName LIKE ''ADDICTION ADVICE%'' THEN ''ADDICTION ADVICE''
WHEN ac.accountName LIKE ''AIA%'' THEN ''AIA''
...
Когда я стал использовать его в своем операторе select - запрос просто возвратил оператор case в виде текста и не оценил его.
Я также не смог использовать его в группе - я получил это сообщение об ошибке:
Each GROUP BY expression must contain at least one column that is not an outer reference.
В идеале я хотел бы, чтобы CASE находился в одном месте - чтобы у меня не было возможности обновить одну строку и не копировать ее в другом месте.
Есть ли способ сделать это?
Я открыт для других способов (как, возможно, функция - но я не уверен, как использовать их, как это)
Вот образец SELECT, который я сейчас использую
SELECT
SUM(c.charge_amount) AS GSTExcl
,dl.FirstDateOfMonth AS MonthBilled
,dl.FirstDateOfWeek AS WeekBilled
,CASE
WHEN ac.accountName like 'AIR NEW Z%' THEN 'AIR NEW ZEALAND'
WHEN ac.accountName LIKE 'AIR BP%' THEN 'AIR BP'
WHEN ac.accountName LIKE 'ADDICTION ADVICE%' THEN 'ADDICTION ADVICE'
WHEN ac.accountName LIKE 'AIA%' THEN 'AIA'
ELSE ac.accountName
END AS accountName
,dl.FinancialYear
,CONVERT(Date,c.date_charged) AS date_charged
FROM [accession] a
LEFT JOIN account_code ac ON a.account_code_id = ac.account_code_id
LEFT Join charge c ON a.accession_id = c.accession_id
LEFT JOIN dateLookup dl ON convert(date,c.date_charged) = dl.date
WHERE a.datecreated = CONVERT(DATE,now())
GROUP BY
dl.FirstDateOfMonth
,dl.FinancialYear
,dl.FirstDateOfWeek
,CONVERT(Date,c.date_charged)
,CASE
WHEN ac.accountName like 'AIR NEW Z%' THEN 'AIR NEW ZEALAND'
WHEN ac.accountName LIKE 'AIR BP%' THEN 'AIR BP'
WHEN ac.accountName LIKE 'ADDICTION ADVICE%' THEN 'ADDICTION ADVICE'
WHEN ac.accountName LIKE 'AIA%' THEN 'AIA'
ELSE ac.accountName
END
UNION
SELECT
SUM(c.charge_amount) AS GSTExcl
,dl.FirstDateOfMonth AS MonthBilled
,dl.FirstDateOfWeek AS WeekBilled
,CASE
WHEN ac.accountName like 'AIR NEW Z%' THEN 'AIR NEW ZEALAND'
WHEN ac.accountName LIKE 'AIR BP%' THEN 'AIR BP'
WHEN ac.accountName LIKE 'ADDICTION ADVICE%' THEN 'ADDICTION ADVICE'
WHEN ac.accountName LIKE 'AIA%' THEN 'AIA'
ELSE ac.accountName
END AS accountName
,dl.FinancialYear
,CONVERT(Date,c.date_charged) AS date_charged
FROM [accession] a
LEFT JOIN account_code ac ON a.account_code_id = ac.account_code_id
LEFT Join charge c ON a.accession_id = c.accession_id
LEFT JOIN dateLookup dl ON convert(date,c.date_charged) = dl.date
WHERE a.datecreated = DATEADD(YEAR,-1,CONVERT(DATE,now()))
GROUP BY
dl.FirstDateOfMonth
,dl.FinancialYear
,dl.FirstDateOfWeek
,CONVERT(Date,c.date_charged)
,CASE
WHEN ac.accountName like 'AIR NEW Z%' THEN 'AIR NEW ZEALAND'
WHEN ac.accountName LIKE 'AIR BP%' THEN 'AIR BP'
WHEN ac.accountName LIKE 'ADDICTION ADVICE%' THEN 'ADDICTION ADVICE'
WHEN ac.accountName LIKE 'AIA%' THEN 'AIA'
ELSE ac.accountName
END
Цель этого СОЮЗА - вернуть все данные за период времени, а ТАКЖЕ вернуть данные за тот же период времени за 12 месяцев ранее.
РЕДАКТИРОВАТЬ: Добавлен недостающий «CATCH-ALL»
РЕДАКТИРОВАТЬ2: Добавлен второй ½ оператора UNION.
РЕДАКТИРОВАТЬ3: Исправлен GROUP BY, чтобы включить некоторые другие необходимые элементы
источник
WHERE a.datecreated = CONVERT(DATE,now()) OR a.datecreated = DATEADD(YEAR,-1,CONVERT(DATE,now()))
?Ответы:
Один из простых способов избежать повторения выражения CASE - использовать CROSS APPLY следующим образом:
С помощью CROSS APPLY вы назначаете имя своему выражению CASE таким образом, чтобы на него можно было ссылаться в любом месте вашего оператора. Это работает, потому что, строго говоря, вы определяете вычисляемый столбец во вложенном SELECT - безотборном SELECT, который следует за CROSS APPLY.
Это то же самое, что ссылаться на столбец с псевдонимом в производной таблице - технически это вложенный SELECT. Это и коррелированный подзапрос, и производная таблица. В качестве коррелированного подзапроса разрешается ссылаться на столбцы внешней области, а в качестве производной таблицы он позволяет внешней области ссылаться на столбцы, которые он определяет.
Для запроса UNION, использующего одно и то же выражение CASE, вы должны определить его в каждой ветви, для этого нет обходного пути, кроме использования совершенно другого метода замены вместо CASE. Тем не менее, в вашем конкретном случае можно получить результаты без UNION.
Две ноги отличаются только условием ГДЕ. Один имеет это:
а другой это:
Вы можете объединить их так:
и примените его к измененному SELECT в начале этого ответа.
источник
CTE
- я не уверен, что это лучший подход!UNION
и просто включитеdatecreated
столбец в вашеGROUP BY
предложение (и обновитеWHERE
предложение, включив в него обе интересующие вас даты).datecreated
столбец в GROUP BY. Помимо этого, я полностью согласен, они могут просто объединить предложения WHERE и отказаться от UNION.Положите данные в таблицу
и присоединиться к нему.
Таким образом, вы можете избежать обновления данных в нескольких местах. Просто используйте там,
COALESCE
где вам это нужно. Вы можете включить это в CTE илиVIEW
s согласно другим предложениям.источник
Я думаю, что еще один вариант, если вам нужно использовать его несколько раз, будет полезной функция с табличными таблицами.
Ваш выбор будет таким.
Кроме того, я не проверял это, и производительность кода также должна быть определена.
РЕДАКТИРОВАТЬ 1 : Я думаю, что Андрей уже дал один, который использует Cross App, который редактирует код. Ну, это можно централизовать, так как любые изменения в функции будут отражаться во всех, так как вы повторяете то же самое в других частях кода.
источник
Я бы использовал,
VIEW
чтобы сделать то, что вы пытаетесь сделать. Конечно, вы могли бы исправить исходные данные, но часто на этом сайте те, кто задает вопросы (consultants / dbas /), не имеют полномочий делать это. ИспользованиеVIEW
может решить эту проблему! Я также использовалUPPER
функцию - дешевый способ устранения ошибок в подобных случаях.Теперь вы объявляете только
VIEW
один раз и можете использовать его где угодно! Таким образом, у вас есть только одно место, в котором хранится и работает ваш алгоритм преобразования данных, что повышает надежность и надежность вашей системы.Вы также можете использовать CTE ( Common Table Expression ) - см. Нижнюю часть ответа!
Чтобы ответить на ваш вопрос, я сделал следующее:
Создайте образец таблицы:
Вставьте пару примеров записей:
Затем создайте
VIEW
как предложено:Тогда
SELECT
из вашегоVIEW
:Результат:
И вуаля!
Вы можете найти все это на скрипке здесь .
CTE
Подход:То же, что и выше, за исключением того,
CTE
что заменяетсяVIEW
следующим:Результат тот же. Затем вы можете обращаться с
CTE
таблицей так же, как с любой другой таблицей -SELECT
только для s! Скрипка доступна здесь .В целом, я думаю, что
VIEW
подход лучше в этом случае!источник
Встроенный стол
Пропустите союз и используйте там,
OR
где это предложено другими.источник