AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / dba / Perguntas / 63153
Accepted
JohnCand
JohnCand
Asked: 2014-04-15 04:37:17 +0800 CST2014-04-15 04:37:17 +0800 CST 2014-04-15 04:37:17 +0800 CST

Como classifico os resultados de uma consulta recursiva em uma forma de árvore expandida?

  • 772

Vamos supor que você tenha uma nodestabela como esta:

CREATE TABLE nodes (
    node serial PRIMARY KEY,
    parent integer NULL REFERENCES nodes(node),
    ts timestamp NOT NULL DEFAULT now()
);

Ele representa uma estrutura de árvore semelhante a um nó padrão com nós raiz no topo e vários nós filhos pendurados nos nós raiz ou outros nós filhos.

Vamos inserir alguns valores de exemplo:

INSERT INTO nodes (parent) VALUES
  (NULL), (NULL), (NULL), (NULL)
, (1), (1), (1), (1), (6), (1), (6)
, (9), (6), (6), (3), (3), (3), (15);

Agora eu quero recuperar os primeiros 10 nós raiz e todos os seus filhos até uma profundidade de 4:

WITH RECURSIVE node_rec AS (
    (SELECT 1 AS depth, * FROM nodes WHERE parent IS NULL LIMIT 10)

    UNION ALL

    SELECT depth + 1, n.*
    FROM nodes AS n JOIN node_rec ON (n.parent = node_rec.node)
    WHERE depth < 4
)
SELECT * FROM node_rec;

Isso funciona muito bem e me dá o seguinte resultado:

 depth | node | parent 
-------+------+--------
     1 |  1   |
     1 |  2   |
     1 |  3   |
     1 |  4   |
     2 |  5   |  1
     2 |  6   |  1
     2 |  7   |  1
     2 |  8   |  1
     2 | 10   |  1
     2 | 15   |  3
     2 | 16   |  3
     2 | 17   |  3
     3 |  9   |  6
     3 | 11   |  6
     3 | 13   |  6
     3 | 14   |  6
     3 | 18   | 15
     4 | 12   |  9

Como você deve ter notado, não há ORDER BYcláusula, então a ordem não é definida. A ordem que você vê aqui é de nós raiz para nós mais profundos.

Como eu ordenaria os resultados como eles apareceriam em uma exibição em árvore expandida, como você pode ver na imagem de exemplo abaixo?

Exibição em árvore expandida de nós

Basicamente, quero que os nós filhos sejam colocados logo após o nó pai correspondente. Se dois ou mais nós filhos tiverem o mesmo nó pai, quero que eles sejam classificados por seu carimbo de data/hora. Com base no exemplo acima, aqui está a ordem de saída desejada que estou tentando alcançar:

 depth | node | parent | ts
-------+------+--------+---------
     1 |  1   |        | 2014-01-01 00:00:00
     2 |  5   |     1  | 2014-01-01 00:10:00
     2 |  6   |     1  | 2014-01-01 00:20:00
     3 |  9   |     6  | 2014-01-01 00:25:00
     4 |  12  |     9  | 2014-01-01 00:27:00
     3 |  11  |     6  | 2014-01-01 00:26:00
     3 |  13  |     6  | 2014-01-01 00:30:00
     3 |  14  |     6  | 2014-01-01 00:36:00
     2 |  7   |     1  | 2014-01-01 00:21:00
     2 |  8   |     1  | 2014-01-01 00:22:00
     2 |  10  |     1  | 2014-01-01 00:23:00
     1 |  2   |        | 2014-01-01 00:08:00
     1 |  3   |        | 2014-01-01 00:09:00
     2 |  15  |     3  | 2014-01-01 10:00:00
     3 |  18  |     15 | 2014-01-01 11:05:00
     2 |  16  |     3  | 2014-01-01 11:00:00
     2 |  17  |     3  | 2014-01-01 12:00:00
     1 |  4   |        | 2014-01-01 00:10:00
postgresql order-by
  • 1 1 respostas
  • 11376 Views

1 respostas

  • Voted
  1. Best Answer
    Erwin Brandstetter
    2014-04-15T05:57:31+08:002014-04-15T05:57:31+08:00

    Você pode ordenar pelo array que representa o caminho da raiz até a folha:

    Para simplificar, deixei de fora LIMIT(para que também não precisemos de parênteses extras) e WHEREda sua consulta original. Aqueles podem ser adicionados livremente.

    consulta básica

    WITH RECURSIVE node_rec AS (
       SELECT 1 AS depth, *
            , ARRAY[node] AS path
       FROM   nodes
       WHERE  parent IS NULL
    
       UNION ALL
       SELECT r.depth + 1, n.*
            , r.path || n.node
       FROM   node_rec r 
       JOIN   nodes    n ON n.parent = r.node
       )
    SELECT *
    FROM   node_rec
    ORDER  BY path;
    

    O mesmo pode ser simplificado com a cláusula dedicadaSEARCH no Postgres 14 ou posterior:

    WITH RECURSIVE node_rec AS (
       SELECT 1 AS depth, *
       FROM   nodes
       WHERE  parent IS NULL
    
       UNION ALL
       SELECT r.depth + 1, n.*
       FROM   node_rec r 
       JOIN   nodes    n ON n.parent = r.node
       ) SEARCH DEPTH FIRST BY node SET path
    SELECT *
    FROM   node_rec
    ORDER  BY path, ts;
    

    Ordenar por coluna adicional

    Se dois ou mais nós filhos tiverem o mesmo nó pai, quero que eles sejam classificados por seu carimbo de data/hora.

    Nós realmente precisamos classificar pela coluna timestamp tsprimeiro em cada nível, e nodeé apenas um desempate (o timestamp pode não ser único). A solução mais simples é usar ambos como recordtipo:

    WITH RECURSIVE node_rec AS (
       SELECT 1 AS depth, *
             , ARRAY[(ts, node)] AS path
       FROM   nodes
       WHERE  parent IS NULL
    
       UNION ALL
       SELECT r.depth + 1, n.*
            , r.path || (n.ts, n.node)
       FROM   node_rec r 
       JOIN   nodes    n ON n.parent = r.node
       )
    SELECT *
    FROM   node_rec
    ORDER  BY path;
    

    Consulta equivalente e mais simples com a SEARCHcláusula no Postgres 14 ou posterior:

    WITH RECURSIVE node_rec AS (
       SELECT 1 AS depth, *
       FROM   nodes
       WHERE  parent IS NULL
    
       UNION ALL
       SELECT r.depth + 1, n.*
       FROM   node_rec r 
       JOIN   nodes    n ON n.parent = r.node
       ) SEARCH DEPTH FIRST BY ts, node SET path
    SELECT *
    FROM   node_rec
    ORDER  BY path, ts;
    

    Como você pode ver, a nova sintaxe permite especificar várias colunas para a classificação.

    db<>mexa aqui

    • 16

relate perguntas

  • Posso ativar o PITR depois que o banco de dados foi usado

  • Práticas recomendadas para executar a replicação atrasada do deslocamento de tempo

  • Os procedimentos armazenados impedem a injeção de SQL?

  • Sequências Biológicas do UniProt no PostgreSQL

  • Qual é a diferença entre a replicação do PostgreSQL 9.0 e o Slony-I?

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host

    • 12 respostas
  • Marko Smith

    Como fazer a saída do sqlplus aparecer em uma linha?

    • 3 respostas
  • Marko Smith

    Selecione qual tem data máxima ou data mais recente

    • 3 respostas
  • Marko Smith

    Como faço para listar todos os esquemas no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 respostas
  • Marko Smith

    Como usar o sqlplus para se conectar a um banco de dados Oracle localizado em outro host sem modificar meu próprio tnsnames.ora

    • 4 respostas
  • Marko Smith

    Como você mysqldump tabela (s) específica (s)?

    • 4 respostas
  • Marko Smith

    Listar os privilégios do banco de dados usando o psql

    • 10 respostas
  • Marko Smith

    Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Como faço para listar todos os bancos de dados e tabelas usando o psql?

    • 7 respostas
  • Martin Hope
    Jin conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane Como faço para listar todos os esquemas no PostgreSQL? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh Por que o log de transações continua crescendo ou fica sem espaço? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland Listar todas as colunas de uma tabela especificada 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney O MySQL pode realizar consultas razoavelmente em bilhões de linhas? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx Como posso monitorar o andamento de uma importação de um arquivo .sql grande? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas Como posso cronometrar consultas SQL usando psql? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas Como faço para listar todos os bancos de dados e tabelas usando o psql? 2011-02-18 00:45:49 +0800 CST

Hot tag

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve