Você pode criar cláusulas WITH aninhadas para expressões de tabela comuns?

184
WITH y AS (
    WITH x AS (
        SELECT * FROM MyTable
    )
    SELECT * FROM x
)
SELECT * FROM y

Algo assim funciona? Eu tentei antes, mas não consegui fazê-lo funcionar.

Joe Phillips
fonte

Respostas:

302

Embora não esteja estritamente aninhado, você pode usar expressões de tabela comuns para reutilizar consultas anteriores nas subsequentes.

Para fazer isso, o formulário da declaração que você está procurando seria

WITH x AS 
(
    SELECT * FROM MyTable
), 
y AS 
(
    SELECT * FROM x
)
SELECT * FROM y
gastador
fonte
2
Muito obrigado. Eu era capaz de fazê-lo em Oracle: COM J AS (SELECT 1 como um de DUAL), Q AS (SELECT * J., 2 AS DUAS DE J) SELECT * FROM Q
Jason TEPOORTEN
5
isto não está aninhado
symbiont
14
Essencialmente, o post significa que você não pode fazê-lo , mas não é um grande problema.
peterh - Restabelece Monica
2
Sim, esta é uma resposta aceitável, porque o que eu estava tentando alcançar com nidificação é a mesma coisa isso acaba me dando qualquer maneira
Joe Phillips
2
Afirmar que isso não está aninhado, apenas porque a consulta 2 não está entre parênteses da consulta 1, parece um argumento fraco. Eu acho que está aninhado (não aninhado recursivamente), porque a consulta 2 usa o resultado da consulta 1, que ocorre com o aninhamento também. É definido que o aninhamento só pode ocorrer quando um filho está dentro de seus símbolos parênteses (ou similares)?
Christiaan Westerbeek
11

Você pode fazer o seguinte, chamado de 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

Você pode não precisar dessa funcionalidade. Fiz o seguinte apenas para organizar melhor minhas consultas:

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

Com não funciona incorporado, mas funciona consecutivamente

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

EDITAR Corrigida a sintaxe ...

Além disso, dê uma olhada no exemplo a seguir

DEMO SQLFiddle

Adriaan Stander
fonte
0

Essas respostas são muito boas, mas, quanto a encomendar os itens corretamente, é melhor consultar este artigo http://dataeducation.com/dr-output-or-how-i-learned-to-stop -preocupando-e-amando-a-mesclagem

Aqui está um exemplo de sua 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
fonte
Minha pergunta original nunca disse nada sobre a união de dados. Poderia ter sido tão facilmente juntar dados
Joe Phillips
0

Eu estava tentando medir o tempo entre os eventos, com exceção de qual entrada tem vários processos entre o início e o fim. Eu precisava disso no contexto de outros processos de linha única.

Eu usei um select com uma junção interna como minha instrução select no Nth cte. O segundo cte eu precisava extrair a data de início em X e a data de término em Y e usei 1 como um valor de ID para a união esquerda para colocá-los em uma única linha.

Funciona para mim, espero que ajude.

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

.... outros ctes

natur3
fonte
0

O 'With' aninhado não é suportado, mas você sempre pode usar o segundo With como uma subconsulta, por exemplo:

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
fonte
-1

podemos criar cte aninhado. veja o cte abaixo no exemplo

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

select * from cte_data,cte_data1
Subhransu Panda
fonte
4
Você está um pouco atrasado para a festa;)
Joe Phillips
4
e isso é CTEs consecutivos, CTEs não aninhados
Meower68