如何建立MySQL分層遞迴查詢?
P粉329425839
2023-08-23 21:55:29
<p>我有一個MySQL表,如下圖:</p>
<表格類別=“s-table”>
<頭部>
<tr>
id |
名稱 |
parent_id |
</標題>
<正文>
<tr>
19 |
類別1 |
<td style="text-align:center;">0</td>
<tr>
20 |
類別2 |
19 |
<tr>
21 |
類別3 |
20 |
<tr>
22 |
類別4 |
21 |
<tr>
... |
... |
... |
</tbody>
</表>
<p>現在,我想要一個 MySQL 查詢,我只需向其提供 id [例如 <code>id=19</code>],然後我應該獲取其所有子 id [即結果應該有 id ' 20,21,22']....</p>
<p>子層級的層次結構未知;它可能會有所不同......</p>
<p>我知道如何使用 <code>for</code>循環來實現這一點...但是如何使用單一 MySQL 查詢來實現相同的目的?
對於MySQL 8 :使用遞迴
使用
#語法。對於 MySQL 5.x: 使用內聯變數、路徑 ID 或自連接。
MySQL 8
parent_id = 19
中指定的值應設定為您要選擇其所有後代的父級的id
。MySQL 5.x
對於不支援公共表格運算式的 MySQL 版本(最高版本 5.7),您可以使用下列查詢來實現此目的:
這是一個小提琴。
此處,
@pv := '19'
中指定的值應設為您要選擇其所有後代的父級的id
。 p>如果父母有多個孩子,這也會起作用。但要求每筆記錄都滿足
parent_id 條件,否則結果不完整。
查詢內的變數賦值
此查詢使用特定的 MySQL 語法:在執行期間指派和修改變數。對執行順序做了一些假設:
from
子句。這就是@pv
初始化的地方。from
別名檢索的順序對每筆記錄評估where
子句。因此,這裡設定的條件僅包括父級已被識別為位於後代樹中的記錄(主要父級的所有後代都將逐步添加到@pv
)。where
子句中的條件依序求值,一旦總結果確定,求值就會中斷。因此,第二個條件必須位於第二位,因為它將 id 添加到父列表中,並且只有在 id 通過第一個條件時才會發生這種情況。呼叫length
函數只是為了確保此條件始終為真,即使pv
字串由於某種原因會產生虛假值。總而言之,人們可能會發現這些假設風險太大,無法依賴。 文檔警告:
因此,即使它與上述查詢一致,評估順序仍然可能會發生變化,例如,當您新增條件或將此查詢用作較大查詢中的檢視或子查詢時。這是一個將在未來的 MySQL 版本中刪除的「功能」 一>:
如上所述,從 MySQL 8.0 開始,您應該使用遞歸
with
語法。效率
對於非常大的資料集,此解決方案可能會變慢,因為
find_in_set
操作不是在列表中查找數字的最理想方式,當然也不是在達到與傳回的記錄數。替代方案 1:
使用遞迴
,連線
越來越多的資料庫實作SQL:1999 ISO 標準
WITH [RECURSIVE]遞迴查詢的
語法(例如Postgres 8.4 、SQL Server 2005 a>、DB2、Oracle 11gR2 ,SQLite 3.8.4 ,Firebird 2.1 、H2 、HyperSQL 2.1.0 ,Teradata,MariaDB 10.2.2 )。從 版本 8.0 開始,MySQL 也支援它。請參閱此答案的頂部以了解要使用的語法。某些資料庫具有用於分層查找的替代非標準語法,例如CONNECT BY 子句/B19306_01 /server.102/b14200/queries003.htm" rel="noreferrer">Oracle,DB2,Informix、CUBRID a> 和其他資料庫。
MySQL 5.7 版不提供這樣的功能。當您的資料庫引擎提供此語法或您可以遷移到提供此語法的資料庫引擎時,那麼這無疑是最佳選擇。如果沒有,請考慮以下替代方案。
替代方案 2:路徑樣式標識符
如果您指派包含分層資訊(路徑)的 id 值,事情就會變得容易得多。例如,在您的情況下,這可能如下所示:
然後您的
選擇
將如下所示:替代方案 3:重複自連線
如果您知道層次結構樹的深度上限,則可以使用標準
sql
查詢,如下所示:請參閱此小提琴
#where
條件指定您要擷取哪個父代的後代。您可以根據需要擴展此查詢更多級別。