упростить оператор SQL с помощью CTE

У меня есть запрос следующего вида:

SELECT A.a, A.b, B.c,
(CASE WHEN ... THEN ... ELSE ... END) AS CalculatedValue,
B.d
FROM    dbo.TableA A INNER JOIN
        dbo.TableB B ON (...)
WHERE (CASE WHEN ... THEN ... ELSE ... END) BETWEEN @DayStart AND @DayEnd
GROUP BY A.a, (CASE WHEN ... THEN ... ELSE ... END), B.c

чтобы избежать многократного повторения одного и того же выражения: (CASE WHEN ... THEN ... ELSE ... END) я хотел определить CTE и запросить такую ​​таблицу, используя в выборе, где и группировать по выражению CalculatedValue

к сожалению, это не работает, потому что выбор уже должен включать group by при создании CTE

есть ли другой способ не повторять CASE WHEN... столько раз?


person Davide Piras    schedule 08.02.2012    source источник


Ответы (2)


Используйте CROSS APPLY, который можно использовать для определения полей с псевдонимами, а затем обращаться к ним:

SELECT A.a, 
       A.b, 
       B.c,
       CalculatedValue,
       B.d
FROM    
       dbo.TableA A 
INNER JOIN
        dbo.TableB B 
        ON (...)
CROSS APPLY 
        (SELECT (CASE WHEN ... THEN ... ELSE ... END)) CxA(CalculatedValue)
WHERE CalculatedValue BETWEEN @DayStart AND @DayEnd
GROUP BY A.a, CalculatedValue, B.c

CxA — это просто псевдоним, и вы можете назвать его как хотите.

person JNK    schedule 08.02.2012
comment
Спасибо JNK, это решило проблему, такое же время выполнения, но код стал намного чище, чем раньше, +1 и зеленый флаг ;-) - person Davide Piras; 08.02.2012
comment
Рад помочь! Я только недавно узнал об этом сам, и это сделало много вещей проще. - person JNK; 08.02.2012
comment
Инкапсулировать общую логику в функциях с табличным значением становится очень весело. Запросы могут в конечном итоге прочитать table CROSS APPLY udf1 CROSS APPLY udf2 CROSS APPLY udf3 и весь «обычный» SQL будет спрятан! - person MatBailie; 08.02.2012
comment
на самом деле снова проверяя производительность, я вижу, что с повторением кода, но без CROSS APPLY, мой исходный запрос занимает ~ 22 секунды, а с более приятным и аккуратным синтаксисом, а CROSS APPLY занимает ~ 1: 22 секунды, накладные расходы в 1 минуту для более красивого синтаксиса :( Я не могу использовать это так... - person Davide Piras; 13.02.2012
comment
@DavidePiras - он все равно должен рассчитывать только один раз. Если это проблема с производительностью, откройте новый вопрос, и мы, вероятно, сможем помочь, если будем знать структуру таблиц и детали запроса. Я не могу придумать причину, по которой помещение этого в CROSS APPLY вызовет проблемы с производительностью. - person JNK; 13.02.2012

Для вышеизложенного, я думаю, вы могли бы просто сделать два слоя CTE. Первый будет выполнять расчет для всех, второй будет выбирать из первого CTE и фильтровать на основе вычисленного значения. Окончательный запрос будет присоединен к CTE второго уровня.

Просто мысль.

person Bryan    schedule 10.04.2014