2009-08-03 7 views
2

Je représente un arbre dans une table, et je dois être en mesure d'obtenir le nœud racine (TOP ID) d'un élément spécifique. Le nœud racine a toujours un ParentID de null. Par exemple, si la table ressemble à ceci:Besoin d'aide avec récursivité dans SQL Server 2005

ID ParentID 
1 null 
2 null 
3 null 
4 2 
5 1 
6 2 
7 6 
8 4 
9 8 
10 6 

Lorsque ID=10, le TOP ID = 2; lorsque ID=9, le TOP ID = 3; etc. Est-il possible d'écrire une fonction de serveur SQL, qui renvoie TOP ID lorsqu'il est donné ID?

Répondre

1

La récursivité dans SQL avant SQL 2003 (c'est-à-dire SQL Server 2000) est plutôt moche; Pour chaque niveau de votre arbre, vous devez écrire une déclaration de jointure séparée sur la table d'origine. Pourvu que le nombre de niveaux dans votre hiérarchie soit fixe, vous pouvez écrire quelque chose comme ceci.

create table #Hell (
parent int, 
id int, 
name varchar(30) 
) 

insert into #Hell values (NULL, 1, 'The Boss') 
insert into #Hell values (1, 2, 'The Boss'' PA') 
insert into #Hell values (1, 3, 'Production Director') 
insert into #Hell values (3, 4, 'Jim''l Fixit') 


select * from #Hell H1 
inner join #Hell H2 
ON H1.id=H2.parent 
inner join #Hell H3 
ON H2.id=H3.parent 
WHERE H3.Id=4 --Find the boss for Jim 

drop table #Hell 

Heureusement SQL Server 2005 a une avec expression de table commune qui permet aux opérations récursives à écrire assez facilement. Voir Voir http://www.4guysfromrolla.com/webtech/071906-1.shtml

Vous devez également être au courant des diverses façons de représenter des arbres dans une base de données. Jetez un oeil sur les diapositives sur les arbres dans SQL de cette présentation http://www.slideshare.net/billkarwin/sql-antipatterns-strike-back

+1

Cet opérateur "with" s'appelle en réalité "Common Table Expression" (CTE) et n'est pas une extension spécifique à SQL Server, mais fait partie de la norme SQL: 2003. –

+0

Merci pour une raison quelconque, je pensais que c'était un truc de Microsoft mais en regardant autour de Postgres prend également en charge les CTE en utilisant WITH RECURSIVE. – pjp

2

MSDN a un très bon ensemble d'exemples pour l'utilisation Common Table Expressions pour écrire des requêtes récursives. Ce fut une grande douleur à l'arrière de faire ces derniers avant SQL Server 2005 (traitant de ce problème exact dans une ancienne application Server 2000 en ce moment).

0

MSDN Brough jusqu'à this article qui sera très probablement l'expliquer mieux que vous êtes susceptible d'obtenir dans le format que nous sommes autorisés à ce spectacle.

3

Voici un exemple récursive d'un sproc je qui va trouver le parent (parent ID = null) pour une ID donnée - (@ID) donné au sproc. Est-ce que c'est ce que tu cherches?

WITH recurseUp (ID, ParentID) 
    AS 
    (
     SELECT ID, ParentID 
     FROM myTable 
     WHERE ID = @ID 
     UNION ALL 
     SELECT b.ID, b.ParentID 
     FROM recurseUp a JOIN myTable b 
     ON (a.ParentID = b.ID) 
    ) 
SELECT ID FROM recurseUP WHERE ParentID is null 
+0

Cet exemple fonctionne bien, mais comment mettre tout cela en chose ou fonction sql, est-il imposible? – Vytas

0

C'est possible, mais la seule méthode que je connaisse est d'utiliser un CURSOR et une procédure stockée récursive. C'est une très mauvaise façon de faire les choses du point de vue de la performance (habituellement). Si possible, vous voudrez peut-être considérer le coût d'avoir un nœud parent racine supplémentaire que vous gardez à jour via le code que vous avancez.

+0

CTE rend le processus beaucoup plus facile maintenant dans le serveur 2005 et au-delà. C'est en fait un P.I.T.A. pour Sever 2000 – TheTXI

0
WITH q AS 
     (
     SELECT id, parentID 
     FROM mytable 
     WHERE id = 10 
     UNION ALL 
     SELECT mytable.id, mytable.parentid 
     FROM q 
     JOIN mytable 
     ON  mytable.parentId = q.id 
     ) 
SELECT * 
FROM q 
WHERE parentID IS NULL