¿Se pueden crear cláusulas AN anidadas para expresiones de tabla comunes?

Respuestas:

302

Si bien no está estrictamente anidado, puede usar expresiones de tabla comunes para reutilizar consultas anteriores en las posteriores.

Para hacer esto, la forma de la declaración que está buscando sería

WITH x AS 
(
    SELECT * FROM MyTable
), 
y AS 
(
    SELECT * FROM x
)
SELECT * FROM y
gastador
fuente
2
Muchas gracias. Pude hacerlo en Oracle: CON J AS (SELECCIONE 1 COMO UNO DE DUAL), Q AS (SELECCIONE J. *, 2 COMO DOS DE J) SELECCIONE * DE Q
Jason TEPOORTEN
55
esto no está anidado
simbionte
14
Esencialmente, la publicación significa que no puedes hacerlo , pero no es un gran problema.
peterh - Restablece a Monica
2
Sí, esta es una respuesta aceptable porque lo que estaba tratando de lograr con la anidación es lo mismo que esto me da de todos modos
Joe Phillips
2
Afirmar que esto no está anidado, solo porque la consulta 2 no está dentro del paréntesis de la consulta 1, suena como un argumento débil. Creo que está anidado (no anidado recursivamente), porque la consulta 2 usa el resultado de la consulta 1, que también ocurre con la anidación. ¿Se define que la anidación solo puede ser cuando un niño está dentro de sus símbolos de paréntesis padre (o similares)?
Christiaan Westerbeek
11

Puede hacer lo siguiente, que se conoce como consulta recursiva:

WITH y
AS
(
  SELECT x, y, z
  FROM MyTable
  WHERE [base_condition]

  UNION ALL

  SELECT x, y, z
  FROM MyTable M
  INNER JOIN y ON M.[some_other_condition] = y.[some_other_condition]
)
SELECT *
FROM y

Es posible que no necesite esta funcionalidad. He hecho lo siguiente solo para organizar mejor mis consultas:

WITH y 
AS
(
  SELECT * 
  FROM MyTable
  WHERE [base_condition]
),
x
AS
(
  SELECT * 
  FROM y
  WHERE [something_else]
)
SELECT * 
FROM x
David Andres
fuente
7

Con no funciona incrustado, pero funciona consecutivamente

;WITH A AS(
...
),
B AS(
...
)
SELECT *
FROM A
UNION ALL
SELECT *
FROM B

EDITAR Se corrigió la sintaxis ...

Además, eche un vistazo al siguiente ejemplo

SQLFiddle DEMO

Adriaan Stander
fuente
0

Estas respuestas son bastante buenas, pero en cuanto a hacer que los artículos se ordenen correctamente, sería mejor que mire este artículo http://dataeducation.com/dr-output-or-how-i-learned-to-stop -pregunta-y-ama-la-fusión

Aquí hay un ejemplo de su consulta.

WITH paths AS ( 
    SELECT 
        EmployeeID, 
        CONVERT(VARCHAR(900), CONCAT('.', EmployeeID, '.')) AS FullPath 
    FROM EmployeeHierarchyWide 
    WHERE ManagerID IS NULL

    UNION ALL

    SELECT 
        ehw.EmployeeID, 
        CONVERT(VARCHAR(900), CONCAT(p.FullPath, ehw.EmployeeID, '.')) AS FullPath 
    FROM paths AS p 
        JOIN EmployeeHierarchyWide AS ehw ON ehw.ManagerID = p.EmployeeID 
) 
SELECT * FROM paths order by FullPath
Don Rolling
fuente
Mi pregunta original nunca dijo nada sobre la unión de datos. Podría haber sido unir datos con la misma facilidad
Joe Phillips el
0

Estaba tratando de medir el tiempo entre eventos con la excepción de qué entrada tiene múltiples procesos entre el inicio y el final. Necesitaba esto en el contexto de otros procesos de una sola línea.

Usé un select con una combinación interna como mi declaración select dentro del Nth cte. El segundo cte que necesitaba para extraer la fecha de inicio en X y la fecha de finalización en Y y usé 1 como valor de identificación para unir a la izquierda y ponerlos en una sola línea.

Funciona para mí, espero que esto ayude.

cte_extract
as 
(
    select ps.Process as ProcessEvent
        , ps.ProcessStartDate 
        , ps.ProcessEndDate 
        -- select strt.*
    from dbo.tbl_some_table ps 
    inner join (select max(ProcessStatusId) ProcessStatusId 
                    from dbo.tbl_some_table 
                where Process = 'some_extract_tbl' 
                and convert(varchar(10), ProcessStartDate, 112) < '29991231'
                ) strt on strt.ProcessStatusId = ps.ProcessStatusID
), 
cte_rls
as 
(
    select 'Sample' as ProcessEvent, 
     x.ProcessStartDate, y.ProcessEndDate  from (
    select 1 as Id, ps.Process as ProcessEvent
        , ps.ProcessStartDate 
        , ps.ProcessEndDate
        -- select strt.*
    from dbo.tbl_some_table ps 
    inner join (select max(ProcessStatusId) ProcessStatusId 
                    from dbo.tbl_some_table 
                where Process = 'XX Prcss' 
                and convert(varchar(10), ProcessStartDate, 112) < '29991231'
                ) strt on strt.ProcessStatusId = ps.ProcessStatusID
    ) x
    left join (
        select 1 as Id, ps.Process as ProcessEvent
            , ps.ProcessStartDate 
            , ps.ProcessEndDate
            -- select strt.*
        from dbo.tbl_some_table ps 
        inner join (select max(ProcessStatusId) ProcessStatusId
                    from dbo.tbl_some_table 
                    where Process = 'YY Prcss Cmpltd' 
                    and convert(varchar(10), ProcessEndDate, 112) < '29991231'
                    ) enddt on enddt.ProcessStatusId = ps.ProcessStatusID
            ) y on y.Id = x.Id 
),

.... otros ctes

natur3
fuente
0

'With' anidado no es compatible, pero siempre puede usar el segundo With como subconsulta, por ejemplo:

WITH A AS (
                --WITH B AS ( SELECT COUNT(1) AS _CT FROM C ) SELECT CASE _CT WHEN 1 THEN 1 ELSE 0 END FROM B --doesn't work
                SELECT CASE WHEN count = 1 THEN 1 ELSE 0 END AS CT FROM (SELECT COUNT(1) AS count FROM dual)
                union all
                select 100 AS CT from dual
           )
              select CT FROM A
KOBER
fuente
-1

podemos crear cte anidado. Por favor, vea el cte a continuación en el ejemplo

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

select * from cte_data,cte_data1
Panda Subhransu
fuente
44
Llegas un poco tarde a la fiesta;)
Joe Phillips
44
y eso es CTE consecutivos, no CTE anidados
Meower68