簡體   English   中英

在遞歸SQL查詢中檢索特定級別

[英]Retrieve specific level in recursive SQL query

我正在處理一個非常復雜的查詢,其中一部分必須檢索與產品關聯的類別。 類別以遞歸方式存儲在Category表中。 產品類別映射位於ProductCategory表中(從技術上講,單個產品可以具有多個類別,但是現在讓我們將其保留在表中,除非它是一個易於解釋的變量)。

Category表非常簡單。 一列是CategoryID ,另一列是ParentCategoryID ,第三列是Name列。 由此,類別被嵌套。 ProductCategory表也​​很簡單。 一列是ProductID另一列是CategoryID

我需要檢索任何給定產品的最高和第二高的類別。 然后,我在帶有一些分析的報告中使用此信息。 我的解決方案確實很慢,擴展性也不佳。 我不知道如何才能更有效地提取所需的數據。

我的解決方案嘗試做的是將所有屬於特定產品類別的父類別歸並在一起,然后獲取我找到的最后兩個類別並將其返回。 我將其作為一個標量函數來完成,在該函數中,我發送了當前的CategoryID和要返回的級別,因此,一個呼叫為0,另一個呼叫為1。

我的示例代碼:

WITH Categories AS (
    SELECT DISTINCT
        CategoryID
    FROM
        ProductCategory
), CategoriesAtDepth AS (
    SELECT
        Categories.CategoryID
        , dbo.WR_f_GetCategoryIDAtDepth(Categories.CategoryID, 0) AS TopCategory
        , dbo.WR_f_GetCategoryIDAtDepth(Categories.CategoryID, 1) AS SecondCategory
    FROM
        Categories
)
SELECT
    CategoriesAtDepth.CategoryID
    , c1.Name AS TopCategory
    , c2.Name AS SecondCategory
FROM
    CategoriesAtDepth LEFT JOIN
    Category AS c1 ON CategoriesAtDepth.TopCategory = c1.CategoryID LEFT JOIN
    Category AS c2 ON CategoriesAtDepth.SecondCategory = c2.CategoryID

和功能代碼:

CREATE FUNCTION WR_f_GetCategoryIDAtDepth 
(
    @CategoryID AS int
    ,@Depth AS int = 0
)
RETURNS int
AS
BEGIN

    -- Declare the return variable here
    DECLARE @Result int
    DECLARE @CurrentHeight int = 0
    DECLARE @CurrentCategoryID int = @CategoryID
    DECLARE @CategoryLevels table
    (
        Height int
        ,CategoryID int
    )

    BEGIN
        --Populate a table with all the categoy IDs in the chain
        WHILE @CurrentCategoryID > 0
        BEGIN
            INSERT INTO @CategoryLevels (Height, CategoryID) VALUES (@CurrentHeight + 1, @CurrentCategoryID)
            SET @CurrentCategoryID = (SELECT ParentCategoryID FROM Category WHERE CategoryID = ISNULL((SELECT CategoryID FROM @CategoryLevels WHERE Height = @CurrentHeight + 1), 0))
            SET @CurrentHeight = @CurrentHeight + 1
        END
        SET @Result = (SELECT CategoryID FROM @CategoryLevels WHERE Height = (@CurrentHeight - @Depth))
    END

    -- Return the result of the function
    RETURN @Result

END
GO

我考慮了@George Mavritsakis關於使用遞歸CTE的評論,並決定嘗試在函數中實現它,並提出了一個更快的解決方案:

CREATE FUNCTION WR_f_GetCategoryIDAtDepth 
(
    @CategoryID AS int
    ,@Depth AS int = 0
)
RETURNS int
AS
BEGIN

    -- Declare the return variable here
    DECLARE @Result int
    DECLARE @CategoryLevels table
    (
        Height int
        ,CategoryID int
    )

    BEGIN
        --Populate a table with all the categoy IDs in the chain
        WITH Base AS (
            SELECT
                0 AS Height
                , @CategoryID AS CategoryID

            UNION ALL

            SELECT
                Height + 1
                , ParentCategoryID
            FROM
                Category INNER JOIN
                    Base ON Category.CategoryID = Base.CategoryID
        )
        INSERT INTO @CategoryLevels (Height, CategoryID)
            SELECT * FROM Base

        SET @Result = (SELECT CategoryID FROM @CategoryLevels WHERE Height = ((SELECT MAX(Height) FROM @CategoryLevels) - @Depth - 1))
    END

    -- Return the result of the function
    RETURN @Result

END
GO

您必須研究遞歸CTE: http : //technet.microsoft.com/zh-cn/library/ms186243%28v=sql.105%29.aspx

解決方案的速度很慢,因為您多次使用WR_f_GetCategoryIDAtDepth函數查詢 Category表。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM