Question

J'ai une table similaire à ceci:

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

Je peux utiliser la parentid champ d'organiser les données dans une structure en arbre.

Voici maintenant le peu que je ne peux pas savoir.Étant donné un parentid, est-il possible d'écrire une instruction SQL pour ajouter tous les champs de la valeur en vertu de cette parentid et une boucle en bas de la branche de l'arbre ?

Mise à JOUR: Je suis l'aide de posgreSQL de sorte que la fantaisie MS-SQL fonctionnalités ne sont pas disponibles pour moi.En tout cas, j'aimerais que ce soit traitée comme un générique SQL question.

BTW, je suis très impressionné d'avoir 6 réponses dans les 15 minutes de poser la question!Aller débordement de pile!

Était-ce utile?

La solution

Il ya quelques façons de faire ce que vous avez besoin dans PostgreSQL.

Quelque chose comme ceci:

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

Autres conseils

Voici un exemple de script utilisant l'expression de table commune:

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

Le script ci-dessus crée un "virtuel" table appelée sumthis qui a des colonnes id et val.Il est défini comme le résultat de deux sélectionne fusionné avec union all.

Première select obtient la racine (where id = :selectedid).

Deuxième select suit les enfants de la précédente, les résultats de manière itérative jusqu'à ce qu'il n'y a rien de revenir.

Le résultat peut ensuite être traitée comme un tableau normal.Dans ce cas, le val de la colonne est résumée.

Depuis la version 8.4, PostgreSQL a requête récursive de soutien pour les expressions de table communes à l'aide de la norme SQL WITH la syntaxe.

Si vous voulez une solution portable qui fonctionne sur n'importe quel ANSI SQL-92 SGBDR, vous aurez besoin d'ajouter une nouvelle colonne à votre table.

Joe Celko est l'auteur original de la Ensembles Imbriqués approche pour le stockage des hiérarchies dans SQL.Vous pouvez Google "imbriqués définit la" hiérarchie pour comprendre plus au sujet de l'arrière-plan.

Ou vous pouvez simplement renommer parentid à leftid et ajouter un rightid.

Voici ma tentative de résumer Imbriquée Ensembles, qui va tomber lamentablement court car je ne suis pas Joe Celko:SQL est un langage basé sur, et de la proximité du modèle (stockage parent ID) n'est PAS un jeu basé sur la représentation d'une hiérarchie.Il n'est donc pas pure, basés sur la méthode de la requête d'un schéma d'adjacence.

Cependant, la plupart des grandes plates-formes ont introduit des extensions au cours des dernières années pour faire face à ce problème précis.Donc, si quelqu'un répond avec une Postgres-solution spécifique, utilisez-le par tous les moyens.

D'une manière standard de faire une requête récursive dans SQL sont récursives CTE. PostgreSQL les prend en charge depuis 8.4.

Dans les versions antérieures, vous pouvez écrire un ensemble récursif-de retour de la fonction:

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)

Voir cet article:

Si vous utilisez SQL Server 2005, il y a une façon vraiment cool pour ce faire à l'aide d'Expressions de Table Communes.

Il prend tous les gruntwork de la création d'une table temporaire, et fondamentalement vous permet de tout faire avec, juste un AVEC et un SYNDICAT.

Voici un bon tutoriel:

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

l'utilisation d'un expression de table commune.

Peut vouloir indiquer c'est SQL Server 2005 ou au-dessus seulement. Dale Ragan

voici un article sur la récursivité par SqlTeam sans expressions de table communes.

Le code suivant compile et il est testé 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';

La condition "de l'enfant <> parent" est nécessaire dans mon cas parce que les noeuds point à eux-mêmes.

Amusez-vous :)

Oracle a "START" et "se CONNECTER EN"

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

Juste une brève de côté, bien que la question a été répondue très bien, il convient de noter que si nous traitons cela comme un:

générique SQL question

puis le SQL de mise en œuvre est assez simple, comme SQL'99 permet linéaire de la récursivité dans le cahier des charges (même si je ne crois pas le Sgbdr mettre en œuvre la norme entièrement) par le biais de la WITH RECURSIVE l'énoncé.Donc, à partir d'un point de vue théorique, nous pouvons faire de ce droit maintenant.

Aucun des exemples travaillé sur OK pour moi donc je l'ai résolu comme ceci:

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;

est-ce SQL Server?Ne pourrait-on pas écrire une TSQL procédure stockée qui boucle et les syndicats les résultats de l'ensemble?

Je suis également intéressé si il y a un SQL seule façon de le faire bien.À partir de l'bits je me souviens de mes bases de données géographiques de classe, il devrait y être.

Je pense que c'est plus facile dans SQL 2008 avec HierarchyID

Si vous avez besoin de stocker arbitraire graphiques, et pas seulement des hiérarchies, de pousser des Postgres sur le côté et essayer un graphique de base de données tels que AllegroGraph:

Tout dans le graphique de la base de données est stockée comme un triple (nœud source, edge, nœud cible) et il vous donne le soutien de première classe pour la manipulation de la structure graphique et d'interrogation à l'aide de SQL comme langage.

Il ne s'intègre pas bien avec quelque chose comme Hibernate ou ORM de Django, mais si vous êtes sérieux au sujet de graphe structures (et pas seulement des hiérarchies comme l'Ensemble Imbriqué modèle vous donne) check it out.

Je crois aussi que l'Oracle a finalement ajouté un support pour de vrai Graphiques dans leurs derniers produits, mais je suis étonné de voir qu'il a fallu si longtemps, beaucoup de problèmes pourraient bénéficier de ce modèle.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top