SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =====================================================================
-- Author: Pavel Celba
-- Create date: 2009-10-22
-- Description: Retrieve the whole company structure from given member
-- =====================================================================
CREATE PROCEDURE dbo.sp_GetCompanySpider
@CompanyID int
AS
BEGIN
SET NOCOUNT ON;
-- Return nulls for no parameters or company which does not exist
IF @CompanyID IS NULL OR NOT EXISTS (SELECT CompanyID FROM Nodes WHERE CompanyID = @CompanyID)
BEGIN
SELECT null AS CompanyID, null AS ParentID
RETURN
END
-- Temporary results table
CREATE TABLE #AllParents (CompanyID int, ParentID int, IsCyclic bit, IsProcessed bit)
-- Look for all parents
INSERT INTO #AllParents
SELECT CompanyID, ParentID, 0,
CASE WHEN ParentID IS NULL THEN 1 ELSE 0 END
FROM Nodes
WHERE CompanyID = @CompanyID
DECLARE @cID int, @pID int, @ccID int, @ppID int
WHILE EXISTS (SELECT 1 FROM #AllParents WHERE isProcessed = 0)
BEGIN
SELECT TOP 1 @pID = ParentID, @cID = CompanyID
FROM #AllParents
WHERE isProcessed = 0
UPDATE #AllParents SET isProcessed = 1
WHERE ParentID = @pID AND CompanyID = @cID
DECLARE par CURSOR FOR
SELECT CompanyID, ParentID
FROM Nodes
WHERE CompanyID = @pID
OPEN par
FETCH NEXT FROM par INTO @ccID, @ppID
WHILE @@FETCH_STATUS = 0
BEGIN
UPDATE #AllParents SET IsCyclic = 1
WHERE CompanyID = @ccID AND (ParentID = @ppID OR (@ppID is NULL AND ParentID is null))
IF @@RowCount = 0
INSERT INTO #AllParents
VALUES (@ccID, @ppID, 0, CASE WHEN @ppID IS NULL THEN 1 ELSE 0 END)
FETCH NEXT FROM par INTO @ccID, @ppID
END
CLOSE par
DEALLOCATE par
END
-- Now we have all parents so we may look for children
-- Mark top-most parents and cyclic parents as not processed to process them again
UPDATE #Allparents SET IsProcessed = 0 WHERE ParentID IS NULL OR IsCyclic = 1
CREATE TABLE #Rslt (CompanyID int, ParentID int)
WHILE EXISTS (SELECT 1 FROM #AllParents WHERE isProcessed = 0)
BEGIN
SELECT TOP 1 @cID = CompanyID, @pID = ParentID
FROM #AllParents
WHERE isProcessed = 0
UPDATE #AllParents SET isProcessed = 1
WHERE CompanyID = @cID AND (ParentID = @pID OR (@pID is NULL AND ParentID is null))
DECLARE chld CURSOR FOR
SELECT CompanyID, ParentID
FROM Nodes
WHERE ParentID = @cID
OPEN chld
FETCH NEXT FROM chld INTO @ccID, @ppID
WHILE @@FETCH_STATUS = 0
BEGIN
IF NOT EXISTS (SELECT CompanyID FROM #Rslt WHERE CompanyID = @ccID AND ParentID = @ppID)
BEGIN
INSERT INTO #Rslt VALUES (@ccID, @ppID)
INSERT INTO #AllParents VALUES (@ccID, @ppID, 0, 0)
END
FETCH NEXT FROM chld INTO @ccID, @ppID
END
CLOSE chld
DEALLOCATE chld
END
--SELECT * FROM #Allparents
SELECT * FROM #Rslt
END
GO
|