2011-09-05 2 views
6

Этот вопрос был задан несколько другие времена, но я до сих пор не удалось разобраться в правильный ответ или правильный способ сделать это:Как гнездо КТР правильно

...

;WITH CTE AS 
(
    SELECT * FROM ... 
) 
SELECT *, [dbo].[udf_BetaInv](A, B, C, D) AS 'Loss' 
FROM CTE 
WHERE (Loss >= @MinRetention) 

Этот не работает, и я не могу создать хранимую процедуру, я не могу использовать Loss в WHERE, потому что не существует в этой области.

Я хотел бы использовать другой КТР, чтобы обернуть это один, так что я могу поставить, где на внешней один, но не кажется, не работает, попытался это:

;WITH CTE AS 
(
    SELECT * FROM ... 
) 
SELECT *, [dbo].[udf_BetaInv(A, B, C, D) AS 'Loss' 
FROM CTE, 
RESULTS AS 
(SELECT * FROM CTE) 
    SELECT * 
    FROM RESULTS 
    WHERE (Loss >= @MinRetention) 

Но он не компилируется в SQL Server, я получаю сообщение об ошибке, что '(' неправильно размещает много строк выше, но не имеет никакого отношения, если я удаляю второй CTE, он отлично работает.

Я только хочу избежать дублирования кода, не хочу называть мой [ udf_BetaInv] дважды в выборе, а также в месте.

+0

Вы имеете в виду '[Loss]' (название столбца) не '' Loss'' (строка)? Не уверен, что это приведет к ошибке, хотя – Rup

ответ

13

У вас есть промежуточный SELECT, которого у вас не должно быть. Это должно работать:

;WITH CTE AS 
(
    SELECT * FROM ... 
), 
RESULTS AS 
(
    SELECT *, [dbo].[udf_BetaInv(A, B, C, D) AS 'Loss' 
    FROM CTE 
) 
SELECT * 
FROM RESULTS 
WHERE (Loss >= @MinRetention) 
+0

Спасибо, отлично поработали, не понимал, что у меня слишком много SELECT: D –

+1

Это не обязательно, но хорошая оценка, чтобы явно указывать столбцы в вашем имени CTE, т. е. .... РЕЗУЛЬТАТЫ ([имена столбцов от CTE], потеря) .... Вы поблагодарите себя позже: P. – deutschZuid

7

Очевидно, что проблема em с первым запросом заключается в том, что «Loss» является просто псевдонимом столбца и не может использоваться в предложении WHERE. Вы правы, что использование этого в CTE позволит избежать дублирования выражения. Вот как вы это сделаете;

WITH CTE AS 
( 
    SELECT * FROM ... 
), 
CteWithLoss AS ( 
    SELECT *, [dbo].[udf_BetaInv](A, B, C, D) AS 'Loss' 
    FROM CTE 
) 
SELECT * 
FROM CteWithLoss 
WHERE (Loss >= @MinRetention); 

На стороне записки: Смотрите, если вы можете сломать привычку, начиная ваши определения КТРА с ;WITH и вместо того, чтобы войти в привычку прекращения всех операторов SQL с запятой. Это более читаемая и лучшая практика.

+0

спасибо отлично работает сейчас :) –

+0

Мне нужен второй CTE внутри первого, от него зависит запрос. Есть ли способ сделать это? – Akbari

+0

Плюс один для «нарушить привычку запускать определения CTE с помощью WITH» – DaveBoltman

0

Ниже приведен пример вложенного CTE.

with cte_data as 
(
    Select * from [HumanResources].[Department] 
),cte_data1 as 
(
    Select * from cte_data 
) 

select * from cte_data1 
+0

Это не вложенный, просто другой CTE, ссылающийся на более ранний. – DaveBoltman

+0

Это вложенный Дэйв. На самом деле это в значительной степени определение вложенного CTE. Вы думали о рекурсивном CTE? Это совершенно новая игра с мячом и намного больше удовольствия, но не то, что запросил ОП. –

Смежные вопросы