SQL Server:如何获取在自引用表中给定父ID的所有子logging

嗨,我有一个引用自己的表,我需要能够select父母和所有它是从一个给定的父母的Id的子logging。

我的表格如下:

ID | ParentID | Name ----------------------- 1 NULL A 2 1 B-1 3 1 B-2 4 2 C-1 5 2 C-2 

所以对于上面的例子,我希望能够传入1的值并获得上面的所有logging。

到目前为止,我已经提出了下面的recursion表值函数,但它不像预期的那样工作(只返回第一条logging)。

 CREATE FUNCTION [dbo].[SelectBranches] ( @id INT ,@parentId INT ) RETURNS @branchTable TABLE ( ID INT ,ParentID INT ,Name INT ) AS BEGIN IF @branchId IS NOT NULL BEGIN INSERT INTO @branchTable SELECT ID ,ParentID ,Name FROM tblLinkAdvertiserCity WHERE ID = @id END INSERT INTO @branchTable SELECT br.ID ,br.ParentID ,br.Name FROM @branchTable b CROSS APPLY dbo.SelectBranches(NULL, b.ParentID) br RETURN END GO 

你可以试试这个

 DECLARE @Table TABLE( ID INT, ParentID INT, NAME VARCHAR(20) ) INSERT INTO @Table (ID,ParentID,[NAME]) SELECT 1, NULL, 'A' INSERT INTO @Table (ID,ParentID,[NAME]) SELECT 2, 1, 'B-1' INSERT INTO @Table (ID,ParentID,[NAME]) SELECT 3, 1, 'B-2' INSERT INTO @Table (ID,ParentID,[NAME]) SELECT 4, 2, 'C-1' INSERT INTO @Table (ID,ParentID,[NAME]) SELECT 5, 2, 'C-2' DECLARE @ID INT SELECT @ID = 2 ;WITH ret AS( SELECT * FROM @Table WHERE ID = @ID UNION ALL SELECT t.* FROM @Table t INNER JOIN ret r ON t.ParentID = r.ID ) SELECT * FROM ret 

除非您使用Oracle,否则您的表结构不适合所描述的问题。 你试图做的是抓取一个层次结构(遍历树结构)。

有一篇文章, SQL中的More Trees&Hierarchies ,描述了解决层次结构问题的一种方法。 他基本上在每一行都添加了一个描述层次的“血统”栏目。

CTErecursion看起来有点贵,所以我写了这个函数,它使用recursion函数调用,但更快的CTErecursion。

 CREATE FUNCTION [dbo].[Fn_GetSubCategories] ( @p_ParentCategoryId INT ) RETURNS @ResultTable TABLE ( Id INT ) AS BEGIN --Insert first level subcategories. INSERT INTO @ResultTable SELECT Id FROM Category WHERE ParentCategoryId = @p_ParentCategoryId OR Id = @p_ParentCategoryId DECLARE @Id INT DECLARE @ParentCategory TABLE(Id INT) DECLARE cur_categories CURSOR LOCAL STATIC READ_ONLY FORWARD_ONLY FOR SELECT Id FROM Category WHERE ParentCategoryId = @p_ParentCategoryId and Id != @p_ParentCategoryId OPEN cur_categories IF @@CURSOR_ROWS > 0 BEGIN FETCH NEXT FROM cur_categories INTO @Id WHILE @@FETCH_STATUS = 0 BEGIN --Insert remaining level sub categories. IF EXISTS(SELECT 1 FROM Category WHERE ParentCategoryId = @Id AND Id != @Id) BEGIN INSERT INTO @ResultTable SELECT DISTINCT C.Id from Fn_GetSubCategories(@Id) C INNER JOIN @ResultTable R ON C.Id != R.Id END FETCH NEXT FROM cur_categories INTO @Id END --Delete duplicate records ;WITH CTE AS (SELECT *,ROW_NUMBER() OVER (PARTITION BY Id ORDER BY Id) AS RN FROM @ResultTable) DELETE FROM CTE WHERE RN<>1 END CLOSE cur_categories DEALLOCATE cur_categories RETURN END