簡體   English   中英

MySQL 中不允許在遞歸公用表表達式中使用 LIMIT

[英]Use of LIMIT in Recursive Common Table Expression is not allowed in MySQL

我的目標是使用最新的 MySQL 的 WITH RECURSIVE 方法構造一棵樹。

我的表稱為categories ,有 2 行。 IDparentID row

我的分類表:

 . ID . | ParentID   
--------|----------
 . 1  . | null  
 . 2  . |  1
 . 3  . |  1  
 . 4  . |  1
 . 6  . |  1
 . 7  . |  1
 . 8  . |  1
 . 9  . |  1
 . 10 . |  1
 . 11 . |  13
 . 12 . |  14
 . 13 . |  12     
 .... . | ...

從 2 到 9 的 ID 具有相同的父級,即 ID = 1 的父級。這就是我試圖通過在我的遞歸公用表表達式的第二個 SELECT 查詢中提供“LIMIT 5”來限制的內容。

上表在樹中的光學表示將類似於以下內容:我的問題是限制同一級別的孩子的數量(在下圖中標記為項目 Y)。

+ Item X .............. (level 1)       
  + Item Y .............. (level 2)  
  + Item Y .............. (level 2)   
  + Item Y .............. (level 2) 
  + .... LIMIT to 5 Items 
+ Item X
    + Item X
      + Item X
         + Item X
             + Item X  
+ Item X

這是我的 mySQL Recursive Common Table Expression查詢,帶有導致問題的 LIMIT 子句:

WITH RECURSIVE cte AS
(
  SELECT ID, 0 AS depth, CAST(ID AS CHAR(200)) AS path
    FROM categories WHERE parentID = 1
  UNION ALL
  SELECT c.ID, cte.depth+1, CONCAT(cte.path, ',', c.ID)
    FROM categories c 
    JOIN cte ON cte.ID = c.parentID
    WHERE FIND_IN_SET(c.ID, cte.path)=0 AND depth <= 10
    LIMIT 5
)

 SELECT * FROM cte

從邏輯上講,我希望通過在 CTE 的第二個 Select 部分中使用 LIMIT 子句來限制第二個 SELECT 語句返回的行數來對我的問題進行排序。 但它給了我一個錯誤:

This version of MySQL doesn't yet support 'ORDER BY / LIMIT over UNION in recursive Common Table Expression'

請注意,我使用的是 MySQL 版本 8.0 +。 我明白錯誤很明顯。 但是,如果我在同一個父母之下有 100 萬個孩子呢? 它會凍結系統!

我將非常感謝一種解決方法。

謝謝你。

如果我正確地跟着你, row_number()可以做你想做的事。 這個想法是枚舉遞歸部分中的categories行,然后過濾前 5 個:

with recursive cte as (
    select id, 0 as depth, cast(id as char(200)) as path
    from categories 
    where parentid = 1
    union all
    select c.id, cte.depth+1, concat(cte.path, ',', c.id)
    from cte
    inner join (
        select c.*, row_number() over(partition by c.parentid order by c.id) rn
        from categories c 
    ) c on cte.id = c.parentid
    where find_in_set(c.id, cte.path) = 0 and depth <= 10 and c.rn <= 5
)
select * from cte

您可以通過預過濾數據集對此進行一些優化:

with recursive 
    cats as (
        select *
        from (
            select c.*, row_number() over(partition by parentid order by id) rn
            from categories c 
        ) t
        where rn <= 5
    ),
    cte as (
        select id, 0 as depth, cast(id as char(200)) as path
        from cats 
        where parentid = 1
        union all
        select c.id, cte.depth+1, concat(cte.path, ',', c.id)
        from cte
        inner join cats c on cte.id = c.parentid
        where find_in_set(c.id, cte.path) = 0 and depth <= 10 and c.rn <= 5
    )
select * from cte

暫無
暫無

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

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