MySQL8.0版本以上支持遞歸查詢
CTE
遞歸 CTE語法規則
WITH RECURSIVE cte_name[(col_name [, col_name] ...)] AS (
initial_query -- anchor member
UNION ALL
recursive_query -- recursive member that references to the CTE name
)
SELECT * FROM cte_name;
遞歸CTE由三個主要部分組成:
- 形成CTE結構的基本結果集的初始查詢(initial_query),初始查詢部分被稱為錨成員。
- 遞歸查詢部分是引用CTE名稱的查詢,因此稱為遞歸成員。遞歸成員由一個
UNION、UNION ALL或者UNION DISTINCT運算符與錨成員相連。 - 終止條件是當遞歸成員沒有返回任何行時,確保遞歸停止。
遞歸CTE的執行順序如下:
- 首先,將成員分為兩個:錨點和遞歸成員。
- 接下來,執行錨成員形成基本結果集(
R0),並使用該基本結果集進行下一次迭代。 - 然后,將
Ri結果集作為輸入執行遞歸成員,並將Ri+1作為輸出。 - 之后,重復第三步,直到遞歸成員返回一個空結果集,換句話說,滿足終止條件。
- 最后,使用
UNION ALL運算符將結果集從R0到Rn組合。
遞歸示例
遞歸輸出1-10序列
WITH RECURSIVE seq_num(n) as (
select 1
UNION ALL
select n+1 from seq_num where n < 10
)
select * from seq_num;
遞歸由下向上查詢
WITH RECURSIVE organ_rec (organCode,parentCode)as (
select organCode,parentCode from g_organ where organCode ='101.007.009.004.011'
UNION ALL
select g.organCode,g.parentCode from g_organ g INNER JOIN organ_rec on organ_rec.parentCode = g.organCode
)
select organCode,parentCode from organ_rec;
遞歸由上往下查詢
WITH RECURSIVE organ_rec (organCode,parentCode)as (
select organCode,parentCode from g_organ where parentCode ='-1'
UNION ALL
select g.organCode,g.parentCode from g_organ g INNER JOIN organ_rec on organ_rec.organCode = g.parentCode
)
select organCode,parentCode from organ_rec;
行轉列
SET @str ='張三,李四,王五';
WITH RECURSIVE help_topic(help_topic_id) as (
select 1
UNION ALL
select help_topic_id+1 from help_topic where help_topic_id < 10
),
temp_table AS (
select b.help_topic_id,SUBSTRING_INDEX(SUBSTRING_INDEX(@str,',',b.help_topic_id+1),',',-1)
from help_topic b where b.help_topic_id < LENGTH(@str) - LENGTH(REPLACE(@str,',','')) + 1)
select * from temp_table
遞歸CTE的限制
遞歸CTE的查詢語句中需要包含一個終止遞歸查詢的條件。當由於某種原因在遞歸CTE的查詢語句中未設置終止條件時,MySQL會根據相應的配置信息,自動終止查詢並拋出相應的錯誤信息。在MySQL中默認提供了如下兩個配置項來終止遞歸CTE。
- cte_max_recursion_depth:如果在定義遞歸CTE時沒有設置遞歸終止條件,當達到cte_max_recursion_depth參數設置的執行次數后,MySQL會報錯。
- max_execution_time:表示SQL語句執行的最長毫秒時間,當SQL語句的執行時間超過此參數設置的值時,MySQL報錯。
查看cte_max_recursion_depth參數的默認值,並設置。
--- 默認1000
SHOW VARIABLES LIKE 'cte_max%';
--- 會話級別設置該值
SET SESSION cte_max_recursion_depth=999999999;
查看MySQL中max_execution_time參數的默認值,並設置。
--- 0:表示沒有限制
SHOW VARIABLES LIKE 'max_execution%';
---單位為毫秒
SET SESSION max_execution_time=1000;
總結
遞歸查詢時,如果是由上往下查詢時,建議通過類似層級碼或者樹型碼字段,通過關鍵字 LIKE 查詢。
參考:
- https://www.yiibai.com/mysql/recursive-cte.html
- 《MySQL技術大全》
