Registriert seit: 18. Mär 2003
Ort: Berlin
589 Beiträge
Delphi 8 Architect
|
Re: MSSQL Server - Stored Procedure - Rekursive aufrufe.
6. Mai 2004, 22:19
SQL-Code:
-- Tabelle anlegen:
CREATE Table Sippe ( idSippe int identity(1,1) NOT NULL
, idParent int NULL
, Vorname varchar(25) NULL
, Name varchar(25) NULL)
GO
CREATE PROCEDURE pp_GetChildren
( @Root int -- die Id des gesuchten Satzes
, @MaxTiefe int = 10 -- Suchtiefe (Standardwert 10)
, @ResultTabelle varchar(255) = NULL -- bei manuellem Aufruf weglassen!
, @ResultEbene int = NULL -- bei manuellem Aufruf weglassen!
)
AS
BEGIN
DECLARE @TmpTable varchar(255)
, @AktId int
, @AktEbene int
, @i int
, @ SQL nvarchar(2000)
, @DerCursor CURSOR
SET @AktEbene = @ResultEbene+1 -- Ebene für Rekursiven Aufruf erhöhen
SET @MaxTiefe = @MaxTiefe -1 -- Restebenen veringern
IF @ResultEbene IS NULL SET @ResultEbene = 0
IF @ResultTabelle IS NULL BEGIN -- dann müssen wir die temporäre
-- Tabelle erst noch anlegen
-- damit sich verschiedene Client-
-- anwendungen beim Aufruf nicht in's
-- Gehege kommen, basteln wir uns
-- einen noch nicht vorhandenen Namen
SET @i = 0
SET @TmpTable = ' ##TmpGetChld_'+ convert( varchar,@i)
WHILE object_id(' tempdb..'+@TmpTable, ' U') is not null BEGIN
-- wenn die temporäre Tabelle schon vorhanden ist, erhöhen wir @i
-- solange, bis wir einen Tabellennamen erwischen, der noch nicht
-- benutzt ist
SET @i = @i+1
SET @TmpTable = ' ##TmpGetChld_'+ convert( varchar,@i)
END
-- nun legen wir die Tabelle an
EXEC(' CREATE TABLE '+@TmpTable+'
( NR int identity(1,1) NOT NULL
, ItemId int NOT NULL
, Ebene int NOT NULL
)')
-- wenn Die Root im Ergebnis auftauchen soll, müssen wir sie hier
-- in die temporäre Tabelle einfügen: (dazu die nächsten 10 Zeilen
-- "entkommentieren":
-- SET @SQL = '
-- INSERT INTO '+@TmpTable+'
-- ( ItemId
-- , Ebene
-- )
-- VALUES
-- ( @AktId
-- , @ResultEbene
-- )'
-- EXEC sp_ExecuteSql @SQL,N'@AktId int, @AktEbene int',@AktId,@AktEbene
END ELSE BEGIN -- Tabellenname wurde übergeben - also nicht anlegen
SET @TmpTable = @ResultTabelle
END
-- dynamischen Cursor für Suche in aktueller Ebene deklarieren:
SET @ SQL = ' SET @DerCursor = CURSOR FOR
SELECT idSippe
FROM Sippe
WHERE idParent = @Root'
EXEC sp_ExecuteSql @ SQL, N' @DerCursor CURSOR OUTPUT, @Root int', @DerCursor OUTPUT, @Root
OPEN @DerCursor
FETCH NEXT
FROM @DerCursor
INTO @AktId
WHILE @@Fetch_Status = 0 BEGIN -- alle direkten Nachkommen
-- durchgehen und in die Temporäre
-- Tabelle einfügen
SET @ SQL = '
INSERT INTO '+@TmpTable+'
( ItemId
, Ebene
)
VALUES
( @AktId
, @ResultEbene
)'
EXEC sp_ExecuteSql @ SQL,N' @AktId int, @AktEbene int',@AktId,@AktEbene
IF @MaxTiefe > 0 BEGIN -- wenn noch weitergesucht werden soll,
EXEC pp_GetChildren -- ist das der Rekursive Aufruf, um
@AktId -- nach Kindern des aktuellen Kindes zu suchen
, @MaxTiefe
, @TmpTable
, @AktEbene
END
-- nächstes Kind holen:
FETCH NEXT
FROM @DerCursor
INTO @AktId
END
-- dyn. Cursor freigeben:
CLOSE @DerCursor
DEALLOCATE @DerCursor
IF @ResultEbene = 0 BEGIN -- nur ausführen, wenn wir aus der Rekursion
-- wieder "aufgetaucht" und in Ebene 0 sind
SET @ SQL = '
Select A.idSippe
, A.idParent
, A.Vorname
, A.Name
, B.Ebene
FROM Sippe A
INNER JOIN '+@TmpTable+' B
ON B.ItemId = A.idSippe
ORDER BY B.NR'
-- Liefert das letztendliche Resultset:
EXEC (@ SQL)
und temporäre Tabelle freigeben:
if object_id(' tempdb..'+@TmpTable, ' U') is not null EXEC(' DROP TABLE '+@TmpTable)
END
END
GO
füge ein paar Daten in die Tabelle "Sippe" ein
und setze anschließend im QueryAnalyzer ab:
EXEC pp_GetChildren 1,5 -- RootId & SuchTiefe
sollte funktionieren...
Gruß
PS: "pp_" ist willkürlich und steht bei mir für "private procedure"
Tim Leuschner Programmierer = moderner Sysiphos: stets wenn er meint, den Stein seiner Dummheit auf den Berg des Wissens gewuchtet zu haben, erblickt er einen völlig neuen Aspekt und der Dummfels poltert mit Getöse zurück ins Tal der Unwissenheit...
|