O que é descendente de sem e como usar na prática
Se você trabalha com planilhas ou sistemas que organizam dados hierárquicos, provavelmente já se deparou com a necessidade de puxar os descendentes de um registro específico. O termo descendente de sem aparece bastante em ambientes de trabalho com bases de dados relacionais, especialmente quando se trata de estruturas em árvore, organogramas ou listas de dependentes em sistemas governamentais. Não existe uma ferramenta única com esse nome exato nos mercados mais conhecidos. O que acontece é que muitos profissionais acabam chamando o recurso de "descendente de sem" por confusão com nomes similares ou por adaptação interna de softwares que usam siglas parecidas. Vou explicar como fazer isso funcionar do jeito que eu mesmo resolvi, porque a primeira vez que precisei disso foi num projeto de migração de dados e errei feio na configuração.
Como identificar o descendente de sem no seu sistema
A abordagem depende totalmente da plataforma que você está usando. No Excel, por exemplo, você consegue construir uma cadeia de referência usando a função PROCV ou, mais recentemente, XLOOKUP em combinação com uma coluna de ID pai. Já no SQL, o caminho mais limpo é uma CTE recursiva. Aqui vai o meu cenário real. Eu precisava extrair todos os dependentes de matrícula de servidores públicos estaduais. O sistema deles não exportava os descendentes de forma plana — cada registro tinha apenas o ID do pai. Minha primeira tentativa foi rodar um loop simples no Python chamando um SELECT a cada iteração. Funcionou, mas demorou perto de 40 minutos para uma árvore de 3.000 registros. Insuportável.
O workaround que funcionou foi transformar tudo num único SELECT recursivo com CTE: SELECT filho.id, filho.nome, filho.pai_id FROM tabela_servidores filho INNER JOIN cte_ancestres ance ON filho.pai_id = ance.id
Com a CTE correta declarada no início da query, o tempo caiu para segundos. A diferença é brutal e a maioria das pessoas não pensa nisso porque começa pelo caminho mais óbvio, que é o loop imperativo.
Passo a passo prático para montar a consulta
Vamos ao básico. Você precisa de uma tabela com, no mínimo, duas colunas: o ID próprio do registro e o ID do pai. Se sua tabela tiver mais de um nível de profundidade — e quase sempre tem —, o sistema recursivo é obrigatório. Tentar resolver com funções aninhadas de procura direta dá errado quando a árvore ultrapassa três ou quatro níveis. No caso do Excel, o procedimento é diferente. Você cria uma coluna auxiliar chamada "Nível" que conta quantos passos são necessários para chegar até o root. Depois, filtra por nível crescente e vai preenchendo manualmente ou com uma macro VBA simples. Não é elegante, mas funciona para conjuntos pequenos, digamos até 500 linhas. Acima disso, o arquivo trava e você perde mais tempo do que ganha.
👉 Clique no botão abaixo para saber mais sobre o assunto!
Se o seu sistema permitir acesso direto ao banco, aí sim você ganha vantagem. Uma query recursiva bem escrita resolve em poucos segundos o que levaria horas fora dela. O problema é que nem todo mundo tem permissão de acesso ao banco. Nesse caso, a alternativa mais razoável é exportar os dados brutos e rodar um script local com pandas ou sqlite, que tem suporte nativo a CTE a partir da versão 3.8.
Pegadinhas que eu já caí
A primeira armadilha é ciclo infinito. Se por algum motivo de cadastro errôneo um registro referencia seu próprio pai, a recursão entra em loop e a query ou o script trava sem aviso. Sempre coloque um limite máximo de profundidade. No SQLServer, você usa OPTION (MAXRECURSION n). No SQLite via Python, você conta as iterações e para se passar de 50 níveis, que é algo que nunca deveria acontecer na prática. A segunda pegadinha é a questão dos dados órfãos. Registros sem pai definido mas que não são root também quebram a lógica se você não tratá-los separadamente. Eu perdi uma tarde inteira caçando um bug que era simplesmente um registro com pai_nulo que estava sendo ignorado pelo filtro inicial. A solução foi rodar um SELECT DISTINCT para mapear todos os IDs pai existentes antes de montar a CTE, garantindo que nada ficasse para fora da árvore.
Também vale avisar sobre performance em bases grandes. Uma árvore com 50 mil nós e profundidade média de 8 níveis roda confortavelmente em PostgreSQL com CTE. Em MySQL anterior à versão 8.0, que não tem suporte a CTE recursiva, você precisa simular com stored procedures ou trazer tudo para fora e processar via código. A diferença de tempo entre essas abordagens pode ser de minutos para horas, dependendo do hardware.
Alternativas quando o descendente de sem não funciona no seu contexto
Se o seu cenário envolve muitas atualizações frequentes e consultas recorrentes, considere armazenar o caminho completo de cada nó usando a extensão postgresql uuid_tree ou o materialized path. Em vez de depender de recursão a cada consulta, você guarda uma string como /1/4/7/12 e faz buscas com LIKE. A desvantagem é que atualizações de estrutura exigem reescrever caminhos inteiros, mas para leitura pesada a economia é enorme. Outra opção é usar uma tabela de adjacência simplificada com cache. Você uma tabela separada que já contains todas as combinações pai-filho calculadas uma vez e consulta ela diretamente. Isso elimina a sobrecarga computacional de recursão repetida, especialmente útil em sistemas web com milhares de requisições simultâneas.
Se nenhuma dessas soluções se encaixa e você está preso a uma planilha com milhares de linhas, o jeito é dividir o problema. Separe os dados em lotes de 1.000 registros, processe cada lote separadamente e depois junte os resultados. É feio, mas evita o travamento do arquivo e ainda assim entrega o que você precisa em poucos minutos. O ponto central é que o conceito de descendente de sem não é uma ferramenta pronta que você baixa e instala. É um padrão de modelagem e consulta que se adapta ao ambiente onde você trabalha. Entender isso antes de começar economiza muito tempo comparado a procurar um software mágico que resolva tudo sozinho. A maioria das pessoas que tenho visto ter sucesso com isso foi exatamente por ter entendido a estrutura dos dados antes de tentar automatizar qualquer coisa.