2008-10-10 4 views
8

Ich habe eine Tabelle in SQL Server, die die normale Baumstruktur von Item_ID, Item_ParentID hat. Angenommen, ich möchte alle CHILDREN einer bestimmten Item_ID (auf jeder Ebene) iterieren und erhalten.Ist die Rekursion in SQL Server gut?

Rekursion scheint ein intuitiver Kandidat für dieses Problem, und ich kann eine SQL Server-Funktion schreiben, um dies zu tun.

Wird sich dies auf die Leistung auswirken, wenn meine Tabelle viele Datensätze enthält? Wie vermeide ich Rekursion und einfach die Tabelle abfragen? Bitte irgendwelche Vorschläge?

Antwort

4

Mit dem neuen MS SQL 2005 konnte man das WITH Stichwort

Check out this question und besonders this answer verwenden.

Mit Oracle könnten Sie CONNECT BY Schlüsselwort verwenden, um hierarchische Abfragen zu generieren (syntax).

AFAIK mit MySQL müssen Sie die Rekursion verwenden.

Alternativ können Sie immer eine Cache-Tabelle für Ihre Einträge bauen Eltern-> Kind-Beziehungen

0

Vielleicht sind noch einige Details in Ordnung.

Wenn Sie eine Master-Detail-Beziehung haben, wie Sie beschreiben, wird dann nicht ein einfaches JOIN bekommen, was Sie brauchen?

Wie in:

SELECT 
    SOME_FIELDS 
FROM 
    MASTER_TABLE MT 
,CHILD_TABLE CT 
WHERE CT.PARENT_ID = MT.ITEM_ID 
1

Verwenden Sie SQL 2005?

Wenn ja, können Sie Common Table Expressions dafür verwenden. Etwas in dieser Richtung:

; 
with CTE (Some, Columns, ItemId, ParentId) as 
(
    select Some, Columns, ItemId, ParentId 
    from myTable 
    where ItemId = @itemID 
    union all 
    select a.Some, a.Columns, a.ItemId, a.ParentId 
    from myTable as a 
    inner join CTE as b on a.ParentId = b.ItemId 
    where a.ItemId <> b.ItemId 
) 
select * from CTE 
0

Sie sollten nicht Rekursion für Kinder brauchen - Sie sind nur auf der Ebene der Suche direkt unter (d select * from T where ParentId = @parent) - Sie brauchen nur Rekursion für alle Nachkommen.

In SQL2005 können Sie die Nachkommen mit bekommen:

with AllDescendants (ItemId, ItemText) as (
    select t.ItemId, t.ItemText 
     from [TableName] t 
    where t.ItemId = @ancestorId 
    union 
    select sub.ItemId, sub.ItemText 
     from [TableName] sub 
      inner join [TableName] tree 
      on tree.ItemId = sub.ParentItemId 
) 
+0

Ich denke, sein Problem ist, er will „Bei ein bestimmtes Niveau ". Wenn Sie nicht wissen, was auf einer bestimmten Ebene ist, ohne root = level 1, root = level 2, children = level 3, etc ... Nicht, dass Rekursion benötigt wird. Aber es kann mehrere Eltern geben. – Cervo

1

Das Problem, das Sie mit Rekursion und Performance konfrontiert wird, ist, wie oft es Rekursion müssen die Ergebnisse zurück. Jeder rekursive Aufruf ist ein weiterer separater Aufruf, der zu den Gesamtergebnissen hinzugefügt werden muss.

In SQL 2K5 Sie eine gemeinsame Tabelle Ausdruck verwenden können diese Rekursion zu behandeln:

ist
WITH Managers AS 
( 
--initialization 
SELECT EmployeeID, LastName, ReportsTo 
FROM Employees 
WHERE ReportsTo IS NULL 
UNION ALL 
--recursive execution 
SELECT e.employeeID,e.LastName, e.ReportsTo 
FROM Employees e INNER JOIN Managers m 
ON e.ReportsTo = m.employeeID 
) 
SELECT * FROM Managers 

oder eine andere Lösung, die Hierarchie in einer anderen Tabelle
MANAGERID (PK

Employee_Managers abzuflachen , FK zur Mitarbeitertabelle)
EmployeeId (PK, FK zur Mitarbeitertabelle)

die Eltern-Kind Alle Beziehung Schiffe würden in dieser Tabelle gespeichert werden, so dass, wenn Manager-1 verwaltet Manager 2 verwaltet Mitarbeiter 3, würde die Tabelle wie folgt aussehen:

ManagerId EmployeeId 
1   2 
1   3 
2   1 

Dies ermöglicht die Hierarchie leicht abgefragt werden:

select * from employee_managers em 
inner join employee e on e.employeeid = em.employeeid and em.managerid = 42 

, die alle Mitarbeiter zurückkehren würde, die Manager haben 42. Der Kopf mehr Leistung sein wird, aber Nachteil der Hierarchie

2

Als allgemeine Antwort werden wird beibehalten, ist es möglich, einige ziemlich anspruchsvolle Sachen in SQL zu tun Server, der nicht benötigt normalerweise Rekursion, einfach durch Verwendung eines iterativen Algorithmus. Es gelang mir, einen XHTML-Parser in Transact SQL zu erstellen, der erstaunlich gut funktionierte. Der Code-Prettifier, den ich geschrieben habe, wurde in einer gespeicherten Prozedur ausgeführt. Es ist nicht elegant, es ist eher, als würde man Büffel beim Ballet spielen sehen. Aber es funktioniert .

+0

Ich habe einmal einen Video-Player in Transact-SQL geschrieben! :-P –

+0

Sie können, aber es wäre sicherlich viel einfacher, einen XHTML-Parser in Python schreiben/Ruby/C#/Java/Perl/LISP/etc. Und die Leistung wäre wahrscheinlich viel besser .... – Cervo

+0

Nein ehrlich. Es ist hier! http://www.simple-talk.com/sql/t-sql-programming/getting-html-data-workbench/ –

1

Joe Celko hat eine book (< - Link zu Amazon) speziell auf Baumstrukturen in SQL-Datenbanken. Während Sie eine Rekursion für Ihr Modell benötigen würden und dort definitiv ein Potenzial für Performance-Probleme bestehen würde, gibt es alternative Möglichkeiten, eine Baumstruktur zu modellieren, abhängig davon, was Ihr spezifisches Problem beinhaltet, was Rekursion vermeiden und eine bessere Leistung ergeben könnte.

0

Sie brauchen keine Rekursion überhaupt .... Hinweis, änderte ich Spalten ItemID und ItemParentID für eine einfache Eingabe ...

 
DECLARE @intLevel INT 
SET @intLevel = 1

INSERT INTO TempTable(ItemID, ItemParentID, Level) SELECT ItemID, ItemParentID, @intLevel WHERE ItemParentID IS NULL

WHILE @intLevel < @TargetLevel BEGIN SET @intLevel = @intLevel + 1 INSERT INTO TempTable(ItemID, ItemParentID, Level) SELECt ItemID, ItemParentID, @intLevel WHERE ItemParentID IN (SELECT ItemID FROM TempTable WHERE Level = @intLevel-1) -- If no rows are inserted then there are no children IF @@ROWCOUNT = 0 BREAK END

SELECt ItemID FROM TempTable WHERE Level = @TargetLevel