GROUP BY с вложенным выражением case - есть ли способ лучше? - PullRequest
0 голосов
/ 06 мая 2020

SQL server 2012

Я беру полученные комиссионные и умножаю их на разные коэффициенты в зависимости от того, как долго Клиент был Клиентом. Предложение group by довольно прямолинейно. Однако мой select становится неудобным, когда я хочу использовать этот критерий по-разному:

select mp.professionals
    ,case when sl.stmndate < dateadd(year, 3, m.qClientOpenDate) then 'New' else 'Old' end age -- straight forward
    ,case (case when sl.stmndate < dateadd(year, 3, m.qClientOpenDate) then 'New' else 'Old' end) -- nested case
        when 'New' then sum(fees) * 0.5
        when 'Old' then sum(fees) * 0.25
        else 0
    end Credit
    ,case (case when sl.stmndate < dateadd(year, 3, m.qClientOpenDate) then 'New' else 'Old' end) -- nested case
        when 'New' then 'Welcome!'
        when 'Old' then 'Thank you for being a long-time Client!'
    end Greeting
from mattersprofessionals mp
inner join matters m on m.matters = mp.matters
inner join stmnledger sl on sl.matters = mp.matters
group by mp.professionals, case when sl.stmndate < dateadd(year, 3, m.qClientOpenDate) then 'New' else 'Old' end

Полагаю, я должен упомянуть, что это упрощенная версия моих фактических case операторов.

Я надеялся, что есть способ сгруппировать по sl.stmndate < dateadd(year, 3, m.qClientOpenDate) как логическое значение или что-то в этом роде, чтобы мне не приходилось выполнять вложенные выражения case.

Я знаю, что могу выполнить подзапрос на basi c case, а затем выполните другие выражения case во внешнем запросе. Но это всего лишь перестановка той же концепции вложенного случая.

Ответы [ 3 ]

5 голосов
/ 06 мая 2020

Когда значения вычисляются непосредственно из строки, я обычно использую cross apply для этого, поскольку это более кратко, чем добавление производной таблицы / CTE, единственной целью которого является определение псевдонима столбца, но все же необходимо проецировать оставшиеся столбцы и содержат FROM.

Это не вариант для выражений, которые ссылаются на оконные функции или агрегатные функции, но здесь будет работать нормально.

select mp.professionals
    ,ca.age -- straight forward
    ,case ca.age -- nested case
        when 'New' then sum(fees) * 0.5
        when 'Old' then sum(fees) * 0.25
        else 0
    end Credit
    ,case ca.age -- nested case
        when 'New' then 'Welcome!'
        when 'Old' then 'Thank you for being a long-time Client!'
    end Greeting
from mattersprofessionals mp
inner join matters m on m.matters = mp.matters
inner join stmnledger sl on sl.matters = mp.matters
cross apply (select case when sl.stmndate < dateadd(year, 3, m.qClientOpenDate) then 'New' else 'Old' end) ca(age)
group by mp.professionals, ca.age
2 голосов
/ 06 мая 2020

Вы можете немного упростить запрос, предварительно вычислив выражение case в подзапросе:

select
    professionals,
    age,
    sum(fees) * case age 
        when 'New' then 0.5 
        when 'Old' then 0.25 
        else 0 
    end credit,
    case age 
        when 'New' then 'Welcome' 
        when 'Old' then 'Thank you for being a long-time Client!' 
    end greeting
from (
    select 
        mp.professionals,
        case when sl.stmndate < dateadd(year, 3, m.qClientOpenDate) 
            then 'New' 
            else 'Old' 
        end age 
    from mattersprofessionals mp
    inner join matters m on m.matters = mp.matters
    inner join stmnledger sl on sl.matters = mp.matters
) t
group by professionals, age

Примечание: ветвь else в вычислении fees, вероятно, никогда не будет достигнута ( поскольку age всегда принимает значение 'New' или 'Old').

0 голосов
/ 08 мая 2020

Технически я думаю, что ответ на мой вопрос - «Нет». Невозможно сгруппировать по логической части оператора case, чтобы его можно было использовать по-разному внутри select.

Я поддержал ответы GMB и Мартина Смита, поскольку они полезны и познавательный. Я играю с кросс-подачей, это наверняка опыт обучения.

...