如何将CTE与函数结合使用,并以递归方式使用它们?

时间:2014-02-27 14:22:20

标签: sql recursion common-table-expression sql-function

我有一张桌子Element (id int, type nvarchar)。每个元素可能有一个或多个父元素,由某些关系定义,具体取决于它的类型。这些父母可能有自己的一组父母,这取决于它的自己的类型。

我想要查询的是另一个元素的祖先(父母,父母,...)的所有Element条记录。

我已经定义了一个函数,给定idtype,返回该元素的父级列表。

CREATE FUNCTION [dbo].[GetParentElementIds] (   
    @ElementId int,
    @ElementType nvarchar(50)
)
RETURNS @ParentElementIds TABLE (id int primary key not null, type nvarchar(50) not null)
AS
BEGIN
    IF @ElementType = 'channel' BEGIN
        DECLARE @PortId int

        -- Some logic to map the @ElementId to a related @PortId

        INSERT INTO @ParentElementIds VALUES (@PortId, 'port')
    END ELSE IF @ElementType = 'port' BEGIN
        DECLARE @CardId int

        -- Some logic to map the @ElementId to a related @CardId

        INSERT INTO @ParentElementIds VALUES (@CardId, 'card')
    END

    RETURN
END

......而且这项工作本身就是如此。接下来,我想创建一个递归CTE,在其结果集上重复调用GetParentElementIds(),以获取祖先列表。不幸的是,这是我的主计划开始动摇的地方,我对确切的查询语法不太确定:

WITH all_ancestor_elements (element_id, type)
AS (
    SELECT id AS element_id, type FROM Element WHERE id IN (SELECT id FROM dbo.GetParentElementIds(5, 'channel'))
UNION ALL
    SELECT dbo.GetParentElementIds(e.id, e.type) FROM Element e WHERE e.id IN (SELECT element_id FROM all_ancestor_elements)
)

SELECT * FROM all_ancestor_elements;

我得到的错误是:

  

Msg 465,Level 16,State 1,Line 5   子查询中不允许递归引用

任何帮助都会受到影响。我不会被迫采用目前的方法,并乐意欢迎任何更好的方法;这只是我选择的当时看起来最好的路径!

谢谢, 马特

1 个答案:

答案 0 :(得分:1)

问题是你如何在这里调用你的表值函数:

SELECT dbo.GetParentElementIds(e.id, e.type) FROM Element e

你需要使用类似的东西:

SELECT  g.id, g.type
FROM    Element e 
        CROSS APPLY dbo.GetParentElementIds(e.id, e.type) g

我不是100%确定你的确切逻辑,但我猜你的最终查询最终会像:

WITH all_ancestor_elements (element_id, type)
AS (
    SELECT  id AS element_id, type 
    FROM    Element 
    WHERE   id IN (SELECT id FROM dbo.GetParentElementIds(5, 'channel'))
    UNION ALL
    SELECT  g.id, g.type
    FROM    all_ancestor_elements e 
            CROSS APPLY dbo.GetDirectAffectorElementIds(e.element_id, e.type) g
)
SELECT  * 
FROM    all_ancestor_elements;