Pergunta

Eu tenho uma tabela semelhante a este:

CREATE TABLE example (
  id integer primary key,
  name char(200),
  parentid integer,
  value integer);

Eu posso usar o parentid campo para organizar dados em uma estrutura de árvore.

Agora aqui está a pouco eu não posso trabalhar fora.Dado um parentid, é possível escrever uma instrução SQL para adicionar todos os campos de valor em que parentid e recurse para baixo o ramo da árvore ?

ATUALIZAÇÃO: Eu estou usando o posgreSQL, de modo a fantasia MS-SQL funcionalidades não estão disponíveis para mim.Em qualquer caso, eu gostaria de esta ser tratada como um genérico do SQL questão.

BTW, estou muito impressionado ter 6 respostas dentro de 15 minutos de fazer a pergunta!Ir estouro de pilha!

Foi útil?

Solução

Existem algumas maneiras de fazer o que você precisa no PostgreSQL.

Algo como isto:

create or replace function example_subtree (integer)
returns setof example as
'declare results record;
         child record;
 begin
  select into results * from example where parent_id = $1;
  if found then
    return next results;
    for child in select id from example
                  where parent_id = $1
      loop
        for temp in select * from example_subtree(child.id)
        loop
          return next temp;
        end loop;
      end loop;
  end if;
  return null;
end;' language 'plpgsql';

select sum(value) as value_sum
  from example_subtree(1234);

Outras dicas

Aqui está um script de exemplo usando a expressão de tabela comum:

with recursive sumthis(id, val) as (
    select id, value
    from example
    where id = :selectedid
    union all
    select C.id, C.value
    from sumthis P
    inner join example C on P.id = C.parentid
)
select sum(val) from sumthis

O script acima cria um 'virtual' tabela chamada sumthis que tem colunas id e val.Ele é definido como o resultado de dois seleciona mesclado com union all.

Primeira select fica a raiz (where id = :selectedid).

Segunda select segue os filhos dos resultados anteriores iterativamente até que não há nada de voltar.

O resultado final pode então ser processado como uma mesa normal.Neste caso, o val coluna é somado.

Desde a versão 8.4, o PostgreSQL tem consulta recursiva de apoio para expressões de tabela comuns utilizando o padrão SQL WITH a sintaxe.

Se você quer uma solução portátil que irá funcionar em qualquer ANSI SQL-92 RDBMS, você vai precisar adicionar uma nova coluna à tabela.

Joe Celko é o autor original do Conjuntos Aninhados abordagem para o armazenamento de hierarquias no SQL.Você pode Google "aninhadas conjuntos de" hierarquia para entender mais sobre o plano de fundo.

Ou você pode apenas mudar o nome para parentid leftid e adicionar um rightid.

Aqui está a minha tentativa de resumir Conjuntos Aninhados, que vai cair muito curto, porque eu não sou Joe Celko:O SQL é um conjunto de base de língua, e adjacência (modelo de armazenamento de IDENTIFICAÇÃO do pai) NÃO é um conjunto de base de representação de uma hierarquia.Portanto, não há pura conjunto baseado no método para consultar uma adjacência esquema.

No entanto, a maioria das principais plataformas de ter introduzido extensões nos últimos anos para lidar com este problema concreto.Então, se alguém responde com uma Postgres-solução específica, use-o por todos os meios.

Uma forma padrão de fazer uma consulta recursiva em SQL são recursivas CTE. PostgreSQL suporta-los desde que 8.4.

Em versões anteriores, você pode escrever uma recursiva do conjunto-retorno de função:

CREATE FUNCTION fn_hierarchy (parent INT)
RETURNS SETOF example
AS
$$
        SELECT  example
        FROM    example
        WHERE   id = $1
        UNION ALL
        SELECT  fn_hierarchy(id)
        FROM    example
        WHERE   parentid = $1
$$
LANGUAGE 'sql';

SELECT  *
FROM    fn_hierarchy(1)

Consulte este artigo:

Se seu usando o SQL Server 2005, não é uma forma muito legal para fazer isso usando Expressões de Tabela Comuns.

Leva todo o gruntwork a criação de uma tabela temporária e, basicamente, permite que você faça isso tudo com apenas uma COM e uma UNIÃO.

Aqui está um bom tutorial:

http://searchwindevelopment.techtarget.com/tip/0,289483,sid8_gci1278207,00.html

usar um expressão de tabela comum.

Pode querer indicar que este é o SQL Server 2005 ou superior apenas. Dale Ragan

aqui está um artigo na recursão por SqlTeam sem expressões de tabela comuns.

O seguinte código é compilado e testado OK.

create or replace function subtree (bigint)
returns setof example as $$
declare
    results record;
    entry   record;
    recs    record;
begin
    select into results * from example where parent = $1;
    if found then
        for entry in select child from example where parent = $1 and child  parent loop
            for recs in select * from subtree(entry.child) loop
                return next recs;
            end loop;
        end loop;
    end if;
    return next results;
end;
$$ language 'plpgsql';

A condição de "criança <> pai" é necessário no meu caso, porque nós aponte para si.

Divirta-se :)

A Oracle tem "COMEÇAM COM" e "CONECTAR"

select 
    lpad(' ',2*(level-1)) || to_char(child) s

from 
    test_connect_by 

start with parent is null
connect by prior child = parent;

http://www.adp-gmbh.ch/ora/sql/connect_by.html

Assim como uma breve lado, embora a pergunta tenha sido respondida muito bem, deve ser observado que, se nós tratamos isso como um:

SQL genérico pergunta

em seguida, a implementação de SQL é bastante simples, como o SQL'99 permite recursão linear, em que a especificação (embora eu acredite que não RDBMSs implementar o padrão totalmente), através da WITH RECURSIVE instrução.Assim, a partir de uma perspectiva teórica, podemos fazer isso agora.

Nenhum dos exemplos trabalhou OK para mim assim que eu tiver resolvido assim:

declare
    results record;
    entry   record;
    recs    record;
begin
    for results in select * from project where pid = $1 loop
        return next results;
        for recs in select * from project_subtree(results.id) loop
            return next recs;
        end loop;
    end loop;
    return;
end;

é este o SQL Server?Você não poderia escrever um TSQL procedimento armazenado que efetua loops através de sindicatos e os resultados?

Eu também estou interessado se houver um SQL-única maneira de fazê-lo embora.De bits eu lembrar dos meus bancos de dados geográficos de classe, não deve ser.

Eu acho que é mais fácil no SQL 2008 com O tipo de dados HierarchyID

Se você precisar armazenar arbitrário gráficos, não apenas hierarquias, você pode empurrar o Postgres para o lado e tentar um gráfico de banco de dados, tais como AllegroGraph:

Tudo no gráfico de banco de dados é armazenado como uma tripla (nó de fonte, borda, nó de destino) e ele dá a você suporte de primeira classe para manipular o grafo e consulta-lo usando um SQL como linguagem.

Ele não se integra bem com algo como o Hibernate ou Django ORM, mas se você é sério sobre o gráfico de estruturas (não só hierarquias como o Aninhadas modelo de Conjunto dá-lhe) o check-out.

Eu também acredito que a Oracle tem finalmente adicionado um suporte para real Gráficos em seus mais recentes produtos, mas estou impressionado é tomado tanto tempo, muitos problemas poderiam se beneficiar deste modelo.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top