Seções iMasters
PostgreSQL

Queries recursivas em PostgreSQL

Olá! Hoje falarei de um dos recursos de que mais gosto em postgreSQL:
recursividade. É um recurso recente, foi inserido na versão 8.4, por
isso vejo muitas pessoas que ainda não sabem usar ou mesmo nem sabiam da
existência.

Vamos à estrutura de uma query recursiva. Primeiro passo para
construir uma query dessas é descobrir qual a primeira busca que ela
fará, o passo inicial. Por exemplo, se tiveres uma tabela de
funcionários (o script para criar a tabela está no final do artigo) que
pode ter nela uma chave estrangeira para ela mesma indicando o seu
superior, por onde começaríamos nossa busca? Digamos que desejamos todos
os funcionários que trabalhem para o funcionário de id igual a 3, o
primeiro passo seria selecionar todos logo abaixo dele.

Então, nesse caso, teríamos o select a seguir:

select id, nome from funcionario where superior_id =3

Até aqui não temos nada novo, certo? Agora precisamos criar um select
que será executado a cada passo da recursão. No nosso caso, queremos os
funcionários abaixo dele. Assim, o que precisamos é que o superior_id
desse funcionário seja igual ao de quem é funcionário dele ou dele
diretamente, certo? Façamos um esboço disso:

select id, nome from funcionario where superior_id =  …. .id

E agora vem a “mágica”, precisamos unir ambas as partes (UNION ALL)  e
usar comandos sql novos do postgresql, o “with recursive”:

WITH RECURSIVE arvore_funcionarios (id, nome) AS
(
SELECT id, nome FROM funcionario WHERE superior_id =3
UNION ALL
SELECT funcionario.id, funcionario.nome FROM funcionario INNER JOIN arvore_funcionarios ON funcionario.superior_id = arvore_funcionarios.id
)

Somente um aviso aqui. A parte recursiva foi trabalhada para que
tivesse uma união com os dados do passo anterior. Por isso foi usado um
INNER JOIN ali dentro. Essa segunda query sempre terá referência à
própria recursão.

Até aqui temos a estrutura da árvore de funcionários abaixo do
funcionário 3. No primeiro passo, serão trazidos todos os funcionários
logo abaixo dele, logo após, para cada um deles será feito o select que
usa a própria estrutura que chamei de arvore_funcionario (uma recursão
propriamente dita).

Mas falta uma coisa. Agora falta selecionar os registros dessa árvore de funcionários. Isso é simples, veja a seguir:

with recursive arvore_funcionarios (id, nome) as
(
select id, nome from funcionario where superior_id =3
UNION ALL
select funcionario.id, funcionario.nome from funcionario INNER JOIN arvore_funcionarios ON funcionario.superior_id = arvore_funcionarios.id
)
select id, nome from arvore_funcionarios;

E pronto! Temos todos os funcionários abaixo do funcionário 3.

Com pequenos arranjos, podemos obter o custo de pessoal (soma dos
salários) sob uma gerência. Vamos novamente usar como gerente o
funcionario de id igual a 3. Nesse caso, queremos todos abaixo do gerente
e somar seus salários (não excluiremos o salário do gerente porque esse
salário também faz parte do custo de pessoal). O que teríamos de fazer
nesse caso?

Primeiro pegamos o gerente em si:

select id, nome, salario from funcionario where id =3

A parte recursiva seria semelhante à anterior, apenas adicionando a coluna salario, assim não vou repetir essa parte aqui.

Vamos à query final então:

with recursive arvore_funcionarios (id, nome, salario) as
(
select id, nome, salario from funcionario where id =3
UNION ALL
select funcionario.id, funcionario.nome, funcionario.salario from funcionario INNER JOIN arvore_funcionarios ON funcionario.superior_id = arvore_funcionarios.id
)
select sum(salario) as salario_total, count(id) as total_funcionarios from arvore_funcionarios;

Nesse caso, troxe inclusive o total de funcionários abaixo desse gerente.

Muitos outros usos existem para queries recursivas, aqui dei apenas
uma introdução. Contudo, se ficou alguma dúvida ou se precisarem de ajuda
em um caso específico, deixem um comentário.

Abraços!

————————————————————————

Script de criação da tabela funcionário:

create table funcionario
(id bigint,
nome varchar(80),
salario numeric(18,3),
superior_id bigint);
ALTER TABLE funcionario ADD CONSTRAINT pk_funcionario PRIMARY KEY (id);
Comente também

51 Comentários

Rafael Almeida

Achei legal esse recurso mas já testou para verificar se tem algum ganho ou perda de desempenho?

Obrigado e abraço.

    André Fernandes

    Sim, já analisei desempenho e o resultado foi muito animador. Obviamente o desempenho depende muito do número de recursões efetuadas, contudo teve tempo de resposta muito menor de que tentativas de fazer a recursão usando laços em código PL/PgSQL ou mesmo em PL/Perl, salvo em alguns casos de apenas um nivel ou dois níveis.
    Obviamente que se a recursão usando laços (sem uso deste recurso do SQL (WITH RECURSIVE)) fosse feita na aplicação cliente podemos prever perda imensa de performance quando comparado com uma execução usando WITH RECURSIVE, assim não testei esse caso.
    De qualquer forma, isso não significa que queries recursivas sejam a solução perfeita sempre se não forem tomados alguns cuidados: o primeiro é uma modelagem bem feita e que faz uso de recusão apenas onde se faça realmente necessário, o que raramente se vê no mundo profissional, infelizmente. Precisamos notar que a query precisa ser bem elaborada e planejada senão ela mesma será o empecilho no desempenho (queries mal escritas são um problema mais comum de que deveriam ser). Por último, mas não menos importante, os dados e/ou a query usada precisam sempre estar preparados para que não haja possibilidade de loops infinitos ou excessivamente grandes (lembre-se de que cada nível funciona como se fosse um loop na query).

    André Fernandes

    Cometi um erro de português em minha resposta pelo qual peço desculpas: onde estava escrito:
    “Obviamente que se a recursão usando laços (sem uso deste recurso do SQL (WITH RECURSIVE)) fosse feita na aplicação cliente podemos prever perda imensa de performance quando comparado com uma execução usando WITH RECURSIVE, assim não testei esse caso. ”
    deveria estar escrito:
    “Obviamente que se a recursão usando laços (sem uso deste recurso do SQL (WITH RECURSIVE)) fosse feita na aplicação cliente poderíamos prever perda imensa de performance quando comparado com uma execução usando WITH RECURSIVE, assim não testei esse caso. “

Beto Lima

André me tire uma dúvida por favor.
Este recursividade nao seria o mesmo que se usássemos uma função em pl?
digo, porque dentro da recursividade temos um select qualquer concorda?
e numa pl também podemos ter um select qualquer, recebendo parametros ou não.
Não estou falando de performance mas somente para entedimento do real propósito de se usar a recursividade. Achei interessante. A impressão que tive de início é que o uso seria parecido como chamar uma pl, mas sem precisarmos compila-lá. Estou certo?

    André Fernandes

    Recusividade é um recurso comum em programação onde se faz possível definir poucos passos e repetir os mesmos para realizar uma tarefa.
    No exemplo que mencionei temos uma representação de funcionários, sendo que estes podem ter gerentes, que também são funcionários. Se for uma empresa com muitos níveis hierárquicos, esses gerentes poderão ter gerentes acima deles também, e assim por diante, até chegar ao presidente da empresa (que seria o superior de todos os demais neste caso).
    Como não sabemos de antemão quantos níveis teríamos, um SQL sem recursão seria impossível, a não ser que fizéssemos um código (poderia ser em PL/PgSQL, por exemplo) que tivesse uma instrução de loop e dentro deste loop um select buscando o nível seguinte. Dessa forma traríamos todos os níveis necessários. Essa seria a ligação com chamar uma PL., mas não sei se era isso que tinhas imaginado.
    Outro exemplo para reforçar essa idéia, é a de seres vivos em uma cadeia alimentar, um ser vivo é alimento para outro ser vivo, mas este também pode ser alimento para um terceiro ser vivo, e assim por diante, até que cheguemos a um ser vivo que está no topo da cadeia alimentar. Neste caso temos uma recursividade, que poderia ser implementada por meio do recurso mostrado.
    Ficou mais fácil de entender?

Beto Lima

obrigado André, mas sinceramente não ficou mais facil do que antes, claro que entendi a idéia do ser vivo e hierarquia de funcionarios. Mas na prática acredito que o ideal seria ter 2 exemplos, um da forma que já estamos acostumados e a outra com a recursividade. Mas aí cabe a você decidir. Grato mesmo pela colaboração.
Abs…

    André Fernandes

    Desculpe a demora em responder a tua dúvida, estive com uma semana tão atarefada que não tinha conseguido ler teu comentário.
    Vou fazer um exemplo neste caso bem simples, vou utilizar uma tabela de funcionarios (como no artigo acima) e desejo buscar o código de todos os superiores de um funcionário (o gerente direto dele, o superior ao gerente dele, etc.), além dele mesmo, até que estejamos no cargo mais alto da hierarquia.
    Vamos supor que temos uma tabela com 3 campos:
    id – código do funcionario
    nome – nome do funcionario
    superior_id – código do superior desse funcionario

    Com uma função (sem usar SQL recursivo) ficaria com algo assim:

    CREATE OR REPLACE FUNCTION public.superiores (
    p_id integer
    )
    RETURNS SETOF integer AS’
    DECLARE
    w_id integer;
    w_linha record;
    BEGIN
    w_id = p_id;
    while w_id is not null
    loop
    return next w_id;
    select superior_id into w_id from funcionario where id = w_id;
    end loop;
    return;
    END;
    ‘LANGUAGE ‘plpgsql’;

    Para executar teríamos algo como

    select superiores(3);

    Já, com um select recursivo não precisaríamos de um laço nem nada semelhante, ficaríamos com algo assim:

    with recursive q(id) as
    (select 3
    UNION ALL
    select funcionario.superior_id from funcionario inner join q on funcionario.id = q.id and funcionario.superior_id is not null)
    select id from q;

    Muito mais simples, não? Além de não precisarmos de nada além de um select.

    Ficou mais fácil de entender com este exemplo?

Beto Lima

ficou sim, muito obrigado mesmo….

Darlan Martins

estou com uma duvida

Darlan Martins

tenho uma tablea

CREATE TABLE apoio
(
seq_apoio integer NOT NULL,
sig_apoio character varying(300),
des_apoio character varying(300),
seq_apoio_pai integer,
dat_alteracao date,
sit_cancelado character(1),
CONSTRAINT pk_apoio PRIMARY KEY (seq_apoio)
)

Darlan Martins

/* Data for the `public.apoio` table (Records 1 – 36) */

INSERT INTO “public”.”apoio” (“seq_apoio”, “sig_apoio”, “des_apoio”, “seq_apoio_pai”, “dat_alteracao”, “sit_cancelado”)
VALUES (1, ‘ESTADO_CIVIL’, ‘Estado Civil’, NULL, NULL, ‘N’);

INSERT INTO “public”.”apoio” (“seq_apoio”, “sig_apoio”, “des_apoio”, “seq_apoio_pai”, “dat_alteracao”, “sit_cancelado”)
VALUES (2, ‘ESCOLARIDADE’, ‘Escolaridade’, NULL, NULL, ‘N’);

INSERT INTO “public”.”apoio” (“seq_apoio”, “sig_apoio”, “des_apoio”, “seq_apoio_pai”, “dat_alteracao”, “sit_cancelado”)
VALUES (3, ‘SITUACAO_MEMBRO’, ‘Situação do Membro’, NULL, NULL, ‘N’);

INSERT INTO “public”.”apoio” (“seq_apoio”, “sig_apoio”, “des_apoio”, “seq_apoio_pai”, “dat_alteracao”, “sit_cancelado”)
VALUES (4, ‘TIPO_ACEITACAO’, ‘Tipo de Aceitação’, NULL, NULL, ‘N’);

INSERT INTO “public”.”apoio” (“seq_apoio”, “sig_apoio”, “des_apoio”, “seq_apoio_pai”, “dat_alteracao”, “sit_cancelado”)
VALUES (5, ‘TIPO_MEMBRO’, ‘Tipo de Membro’, NULL, NULL, ‘N’);

INSERT INTO “public”.”apoio” (“seq_apoio”, “sig_apoio”, “des_apoio”, “seq_apoio_pai”, “dat_alteracao”, “sit_cancelado”)
VALUES (6, NULL, ‘Solteiro(a)’, 1, NULL, ‘N’);

INSERT INTO “public”.”apoio” (“seq_apoio”, “sig_apoio”, “des_apoio”, “seq_apoio_pai”, “dat_alteracao”, “sit_cancelado”)
VALUES (7, NULL, ‘Casado(a)’, 1, NULL, ‘N’);

INSERT INTO “public”.”apoio” (“seq_apoio”, “sig_apoio”, “des_apoio”, “seq_apoio_pai”, “dat_alteracao”, “sit_cancelado”)
VALUES (8, NULL, ‘Viuvo(a)’, 1, NULL, ‘N’);

INSERT INTO “public”.”apoio” (“seq_apoio”, “sig_apoio”, “des_apoio”, “seq_apoio_pai”, “dat_alteracao”, “sit_cancelado”)
VALUES (9, NULL, ‘Divorciado(a)’, 1, NULL, ‘N’);

INSERT INTO “public”.”apoio” (“seq_apoio”, “sig_apoio”, “des_apoio”, “seq_apoio_pai”, “dat_alteracao”, “sit_cancelado”)
VALUES (10, NULL, ‘Não Alfabetizado’, 2, NULL, ‘N’);

INSERT INTO “public”.”apoio” (“seq_apoio”, “sig_apoio”, “des_apoio”, “seq_apoio_pai”, “dat_alteracao”, “sit_cancelado”)
VALUES (11, NULL, ‘Primario’, 2, NULL, ‘N’);

INSERT INTO “public”.”apoio” (“seq_apoio”, “sig_apoio”, “des_apoio”, “seq_apoio_pai”, “dat_alteracao”, “sit_cancelado”)
VALUES (12, NULL, ‘Ensino Fundamental’, 2, NULL, ‘N’);

INSERT INTO “public”.”apoio” (“seq_apoio”, “sig_apoio”, “des_apoio”, “seq_apoio_pai”, “dat_alteracao”, “sit_cancelado”)
VALUES (13, NULL, ‘Ensino Médio’, 2, NULL, ‘N’);

INSERT INTO “public”.”apoio” (“seq_apoio”, “sig_apoio”, “des_apoio”, “seq_apoio_pai”, “dat_alteracao”, “sit_cancelado”)
VALUES (14, NULL, ‘Superior Completo’, 2, NULL, ‘N’);

INSERT INTO “public”.”apoio” (“seq_apoio”, “sig_apoio”, “des_apoio”, “seq_apoio_pai”, “dat_alteracao”, “sit_cancelado”)
VALUES (15, NULL, ‘Superior Incompleto’, 2, NULL, ‘N’);

INSERT INTO “public”.”apoio” (“seq_apoio”, “sig_apoio”, “des_apoio”, “seq_apoio_pai”, “dat_alteracao”, “sit_cancelado”)
VALUES (16, NULL, ‘Batismo’, 4, NULL, ‘N’);

INSERT INTO “public”.”apoio” (“seq_apoio”, “sig_apoio”, “des_apoio”, “seq_apoio_pai”, “dat_alteracao”, “sit_cancelado”)
VALUES (17, NULL, ‘Transferência’, 4, NULL, ‘N’);

INSERT INTO “public”.”apoio” (“seq_apoio”, “sig_apoio”, “des_apoio”, “seq_apoio_pai”, “dat_alteracao”, “sit_cancelado”)
VALUES (18, NULL, ‘Aclamação’, 4, NULL, ‘N’);

INSERT INTO “public”.”apoio” (“seq_apoio”, “sig_apoio”, “des_apoio”, “seq_apoio_pai”, “dat_alteracao”, “sit_cancelado”)
VALUES (19, NULL, ‘Congregado’, 5, NULL, ‘N’);

INSERT INTO “public”.”apoio” (“seq_apoio”, “sig_apoio”, “des_apoio”, “seq_apoio_pai”, “dat_alteracao”, “sit_cancelado”)
VALUES (20, NULL, ‘Membro’, 5, NULL, ‘N’);

INSERT INTO “public”.”apoio” (“seq_apoio”, “sig_apoio”, “des_apoio”, “seq_apoio_pai”, “dat_alteracao”, “sit_cancelado”)
VALUES (21, NULL, ‘Diacono(a)’, 5, NULL, ‘N’);

INSERT INTO “public”.”apoio” (“seq_apoio”, “sig_apoio”, “des_apoio”, “seq_apoio_pai”, “dat_alteracao”, “sit_cancelado”)
VALUES (22, NULL, ‘Diaconisa’, 5, NULL, ‘S’);

INSERT INTO “public”.”apoio” (“seq_apoio”, “sig_apoio”, “des_apoio”, “seq_apoio_pai”, “dat_alteracao”, “sit_cancelado”)
VALUES (23, NULL, ‘Presbítero’, 5, NULL, ‘N’);

INSERT INTO “public”.”apoio” (“seq_apoio”, “sig_apoio”, “des_apoio”, “seq_apoio_pai”, “dat_alteracao”, “sit_cancelado”)
VALUES (24, NULL, ‘Evangelista’, 5, NULL, ‘N’);

INSERT INTO “public”.”apoio” (“seq_apoio”, “sig_apoio”, “des_apoio”, “seq_apoio_pai”, “dat_alteracao”, “sit_cancelado”)
VALUES (25, NULL, ‘Pastor(a)’, 5, NULL, ‘N’);

INSERT INTO “public”.”apoio” (“seq_apoio”, “sig_apoio”, “des_apoio”, “seq_apoio_pai”, “dat_alteracao”, “sit_cancelado”)
VALUES (26, NULL, ‘Auxiliar’, 5, NULL, ‘N’);

INSERT INTO “public”.”apoio” (“seq_apoio”, “sig_apoio”, “des_apoio”, “seq_apoio_pai”, “dat_alteracao”, “sit_cancelado”)
VALUES (27, NULL, ‘Cooperador’, 5, NULL, ‘N’);

INSERT INTO “public”.”apoio” (“seq_apoio”, “sig_apoio”, “des_apoio”, “seq_apoio_pai”, “dat_alteracao”, “sit_cancelado”)
VALUES (28, NULL, ‘Missionario(a)’, 5, NULL, ‘N’);

INSERT INTO “public”.”apoio” (“seq_apoio”, “sig_apoio”, “des_apoio”, “seq_apoio_pai”, “dat_alteracao”, “sit_cancelado”)
VALUES (29, NULL, ‘Administrador’, 5, NULL, ‘S’);

INSERT INTO “public”.”apoio” (“seq_apoio”, “sig_apoio”, “des_apoio”, “seq_apoio_pai”, “dat_alteracao”, “sit_cancelado”)
VALUES (30, NULL, ‘Maestro’, 5, NULL, ‘S’);

INSERT INTO “public”.”apoio” (“seq_apoio”, “sig_apoio”, “des_apoio”, “seq_apoio_pai”, “dat_alteracao”, “sit_cancelado”)
VALUES (31, NULL, ‘Ativo’, 3, NULL, ‘N’);

INSERT INTO “public”.”apoio” (“seq_apoio”, “sig_apoio”, “des_apoio”, “seq_apoio_pai”, “dat_alteracao”, “sit_cancelado”)
VALUES (32, NULL, ‘Desviado’, 3, NULL, ‘N’);

INSERT INTO “public”.”apoio” (“seq_apoio”, “sig_apoio”, “des_apoio”, “seq_apoio_pai”, “dat_alteracao”, “sit_cancelado”)
VALUES (33, NULL, ‘Falecido’, 3, NULL, ‘N’);

INSERT INTO “public”.”apoio” (“seq_apoio”, “sig_apoio”, “des_apoio”, “seq_apoio_pai”, “dat_alteracao”, “sit_cancelado”)
VALUES (34, NULL, ‘Mudou-se’, 3, NULL, ‘N’);

INSERT INTO “public”.”apoio” (“seq_apoio”, “sig_apoio”, “des_apoio”, “seq_apoio_pai”, “dat_alteracao”, “sit_cancelado”)
VALUES (35, NULL, ‘Excluido’, 3, NULL, ‘N’);

INSERT INTO “public”.”apoio” (“seq_apoio”, “sig_apoio”, “des_apoio”, “seq_apoio_pai”, “dat_alteracao”, “sit_cancelado”)
VALUES (36, NULL, ‘Disciplina’, 3, NULL, ‘N’);

    André Fernandes

    Rapaz, qual tua intenção com isso?

      André Fernandes

      Não sei quem escreveu isto com minha senha, mas esta resposta não é minha.

    Darlan Martins

    Criar um script para que ele monte uma estrutura hierarquica EX:

    Pai 1
    Filho1
    Filho1
    FIlho1
    Pai 2
    Filho2
    Filho2
    Filho2

    dai por diante

Darlan Martins

Preciso Criar com essa estrutura uma querie recursiva Ex:

Pai 1
Filhos1
Filhos1
Filhos1
Pai 2
Filhos2
Filhos2
Filhos2

    André Fernandes

    Darlan, tudo bom?
    Vejamos, seria impossível que você tivesse três filhos pra cada pai, sem nenhuma mãe, isso fica meio difícil. O ideal é que você adicione uma mãe ao menos para cada pai, assim ficaria equilibrado.

    Walquirio Saraiva Rocha

    não precisa de mãe somente o pai e filho na tabela se você fizer um select vc vai ver que seq_apoio = 1 e seq_apoio pai = null então esse 1 é pai e quando tiver o seq_apoio = 2 e seq_apoio_pai = 2 então o 2 não é pai e sim filho logo não precisa de mãe… vou montar o select e passar aqui no forum

    André Fernandes

    Rapaz, onde já se viu ter filhos sem mulher, onde está tua lógica nisso?

      André Fernandes

      Esta resposta não foi escrita por mim, não sei quem foi que conseguiu minha senha e fez uma resposta tola destas, peço desculpas.

Kleber Calegário

Excelente artigo André, nessa nova versão foi implementado mais alguma nova ferramenta?

Abraços.

Kleber

    André Fernandes

    Fala Kleber, tudo bom, obrigado pelo elogio, como vão as coisas?
    Abraços.
    Você continua parecendo o leôncio, rs, até.

      André Fernandes

      Mais uma resposta que não foi escrita por mim, não sei quem foi que escreveu isto, peço desculpas pelo que escreveram em meu nome.

Evandro Rispar

Ótimo Artigo… Gostaria de saber se existe a possibilidade fazer a recursividade em níveis a cima do id, ex: Passo o id do filho e quero que retorne o Pai, e o Filho desse id se houver;

Motta

Faltou apenas :

O Exemplo com o resultado da query

Informar se existe como saber em que nível(level) estamos, importante para montar visualmente uma hierarquia.

    André Fernandes

    Mil desculpas pela demora na resposta, mas se ainda for de ajuda a alguma pessoa, aqui vai a resposta: é sim possível saber o nível hierárquico de cada linha. Modificando levemente nossa query teríamos:

    with recursive arvore_funcionarios (id, nome, nivel) as
    (
    select id, nome, 1 from funcionario where superior_id =3
    UNION ALL
    select funcionario.id, funcionario.nome, nivel+1 from funcionario INNER JOIN arvore_funcionarios ON funcionario.superior_id = arvore_funcionarios.id
    )
    select id, nome, nivel from arvore_funcionarios;

Lucas Moraes

Parabéns! Muito bom artigo.
Como você é DBA, poderia criar um artigo sobre banco de dados temporal com PostgreSQL, seria bacana e a comunidade agradeceria. :)

    André Fernandes

    Lucas, bancos de dados temporais não são usuais e estão fora de moda.
    Hoje há soluções para o tempo já, como o climatempo.com.br g1.com.br/clima etc.

Jackson Jorge

Caramba… Não acredito que é tão simples assim com PG, precisei fazer algo parecido no MySql e só consegui com Stored Procedures e tabela temporária….

Infelizmente devido a falta de tempo não estou conseguindo estudar PG e migrar para ele, mas já está ma minha lista de mudanças à fazer.

Muito bom o artigo, parabéns!

Belchior Palma

ótimo artigo!

teste

ótimo artigo!

Anderson

Me ajudou pra caramba essa function que você criou André, pois como estou usando o postgresql 8.3 não dá para usar o with recursive. Valeu…

    André Fernandes

    Fico feliz que ajudou-te. Sei que nem sempre é possível, mas aconselho-te atualizar a versão do postgreSQL pois há grandes melhorias nas novas versões, inclusive relativas a performance.

Marisergio Alves

André,
Fiquei muito interessado em saber como funciona internamente a recursão em SQL, não somente a sintaxe. Se não for muito incômodo, disponibilise um link de uma boa bibliografia. Gostaria também de saber como é que acontece a parada da recursão em SQL. Obrigado e parabéns.

Wagner Santos

Olá, André!
Cara, segui o exemplo e tive o mesmo problema do Darlan. Estou tentando criar uma hierarquia de setores, no mesmo estilo dessa de funcionários do teu exemplo. Quando rodo minha query, a ordenação está ocorrendo pelo nível. No meu caso, tenho um setor que é o principal (sem pai) e todos os outros vão abaixo dele

Ex.:
- Pai
- – Filho 1
- – Filho 2
- – Filho 3
- – - Filho 1.1
- – - Filho 1.2
- – - Filho 2.1

O exemplo está confuso, mas a query traz o pai em primeiro lugar, logo em seguida todos os seus filhos diretos, depois disso os filhos dos filhos e assim por diante. Quer dizer, eles estão ordenados pelo seu nível de “profundidade” na cadeia, e não hierarquicamente. O ideal seria como no exemplo abaixo.

Ex.:
- Pai
- – Filho 1
- – - Filho 1.1
- – - Filho 1.2
- – Filho 2
- – - Filho 2.1
- – Filho 3

Tens alguma idéia de como posso resolver isso? Procurei informações pela internet mas não encontrei/entendi.

Obrigado pelo artigo! Um abraço!

    Wagner Santos

    Encontrei uma solução, André! Faltou usar um campo do tipo ARRAY pra conseguir ordenar o retorno. Encontrei a informação em http://explainextended.com/2009/07/17/postgresql-8-4-preserving-order-for-hierarchical-query/.
    Abraço!

      André Fernandes

      Wagner (nome do meu vizinho, rs)
      Que bom que encontrou a solução, mas quando for precisar criar vários valores para uma mesma variável, o ideal é que se crie assim:
      Variavel_1 = ’1′
      Variável_2 = ’2′
      Variável_2 = ’3′

      Nunca é bom usar Arrays nesses casos, esse negócio de “vetor[chave] = valor” não funciona muito bem e é ultrapassado, sempre crie uma variável para cada valor.

Alisson

Boa tarde amigo, muito bom seu POST. Não sou DBA, sou um mero programador e estou tendo dificuldade para trazer meus dados. Meu cenário é o seguinte, eu tenho sempre o ULTIMO FILHO, e gostaria de encontrar o PAI FULL deles, para isso, preciso de um SQL Recursivo, certo ??? Tentei seguir seu exemplo, mas ele traz todos os dados da tabela, sendo q gostaria de apenas os filhos, até achar o pai de TAL ITEM. segue abaixo o código:

WITH RECURSIVE arvore (id) AS
(
SELECT cod_item_despesa FROM sisdoc_v2.oog_item_despesa where cod_item_despesa = 15547
UNION ALL
SELECT cod_item_despesa FROM sisdoc_v2.oog_item_despesa INNER JOIN arvore ON cod_item_oog_anterior = arvore.id
)
SELECT cod_item_despesa FROM sisdoc_v2.oog_item_despesa;

Poderia me ajudar e ver aonde estou errando ???

O pai de todos, tem o campo? cod_item_oog_anterior null e seus filhos tem o campo preenchido com a chave primária de seus pais, exemplo:

PAI : PK: 5213 cod_item_oog_anterior: NULL
FILHO: PK: 11339 cod_item_oog_anterior: 5213
FILHO: PK: 13965 cod_item_oog_anterior: 11339
FILHO: PK: 15547 cod_item_oog_anterior: 13965

Obrigado amigo, desde já!

André Fernandes

Estou com raiva da iMaster, segurança falha deles, permite outras pessoas postarem em meu nome. Não postei nem metade desses comentários absurdos daqui.

André Fernandes

Essa pessoa continua postando em meu nome aqui, quando vocês vão corrigir isso?

Qual a sua opinião?