2011-09-05 11 views
6

Esta pregunta se formuló algunas otras veces, pero todavía no ha conseguido resolver la respuesta correcta o adecuada manera de hacer esto:Cómo nido CTE adecuadamente

...

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

Este no funciona y no puedo crear el procedimiento almacenado, claramente no puedo usar Pérdida en el DONDE porque no existe en ese ámbito.

quisiera utilizar otro CTE para envolver éste, así que puede poner el donde por un exterior, pero no no parecen funcionar, probamos este:

;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) 

Pero no se puede compilar en SQL Servidor, me sale un error que indica que '(' se pierde muchas filas pero no tiene nada que ver, si elimino el segundo CTE funciona bien.

Solo quiero evitar la duplicación de código, no quiero llamar a mi [ udf_BetaInv] dos veces en la selección y también en el lugar.

+0

¿Se refiere a '[Loss]' (un nombre de columna) not ''Loss'' (a string)? No estoy seguro si eso causaría el error, aunque – Rup

Respuesta

13

Tiene un intermedio SELECT que no debería tener. Esto debería funcionar:

;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

Gracias, funciona muy bien, no me di cuenta que estaba teniendo demasiados SELECT: D –

+1

No es necesario, pero una buena práctica para nombrar explícitamente las columnas en su nombre CTE, es decir .... RESULTADOS ([nombres de columna de CTE], pérdida) .... Se lo agradecerá más tarde: P. – deutschZuid

7

Obviamente, el probl em con la primera consulta es que 'Pérdida' es solo un alias de columna y no se puede usar en una cláusula WHERE. Tienes razón en que usarlo en un CTE evitaría duplicar la expresión. Así es como lo harías;

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); 

En una nota: ver si puede romper el hábito de comenzar sus definiciones CTE con ;WITH y en lugar de entrar en el hábito de poner fin a todas las sentencias SQL con un punto y coma. Es una práctica más legible y mejor.

+0

gracias funciona perfectamente ahora :) –

+0

Necesito el segundo CTE dentro del primero, la consulta depende de ello. ¿Hay alguna forma de hacerlo? – Akbari

+0

Más uno para "romper el hábito de comenzar sus definiciones de CTE con; WITH" – DaveBoltman

0

A continuación se muestra el ejemplo de anidado CTE.

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

select * from cte_data1 
+0

Eso no está anidado, solo otro CTE que hace referencia a uno anterior. – DaveBoltman

+0

Esto está anidado Dave. De hecho, es más o menos la definición de un CTE anidado. ¿Estabas pensando en los CTE recursivos? Es un juego de pelota completamente nuevo y mucho más divertido, pero no es lo que solicitó el OP. –

Cuestiones relacionadas