>  Q&A  >  본문

MySQL 계층적 재귀 쿼리를 어떻게 생성하나요?

<p>저는 MySQL 表,如下所示:</p> <테이블 클래스="s-테이블"> <머리> <tr> <th style="text-align:center;">id</th> <th style="text-align:center;">이름</th> <th style="text-align:center;">parent_id</th> </tr> </머리> <본문> <tr> <td style="text-align:center;">19</td> <td style="text-align:center;">类别1</td> <td style="text-align:center;">0</td> </tr> <tr> <td style="text-align:center;">20</td> <td style="text-align:center;">类别2</td> <td style="text-align:center;">19</td> </tr> <tr> <td style="text-align:center;">21</td> <td style="text-align:center;">类别3</td> <td style="text-align:center;">20</td> </tr> <tr> <td style="text-align:center;">22</td> <td style="text-align:center;">类别4</td> <td style="text-align:center;">21</td> </tr> <tr> <td style="text-align:center;">...</td> <td style="text-align:center;">...</td> <td style="text-align:center;">...</td> </tr> </tbody> </테이블> <p>现재,我想要一个 MySQL 查询,我只需向其提供 id [例如 <code>id=19</code>],然后我应该获取其所有子 id [即结果应id가 '있습니다. 20,21,22']....</p> <p>子级的层次结构未知;它可能会有所不同......</p> <p>我知道如何使用 <code>for</code> 循环来做到这一点...但是如何使用单个 MySQL은 查询来实现와 유사합니까?</p>
P粉329425839P粉329425839423일 전535

모든 응답(1)나는 대답할 것이다

  • P粉393030917

    P粉3930309172023-08-24 13:05:06

    MySQL 8+의 경우: 재귀적 使用 구문을 사용하세요.
    MySQL 5.x의 경우: 인라인 변수, 경로 ID 또는 자체 조인을 사용합니다.

    MySQL 8+

    으아아아

    parent_id = 19 中指定的值应设置为您要选择其所有后代的父级的 id.

    MySQL 5.x

    공용 테이블 표현식을 지원하지 않는 MySQL 버전(최대 버전 5.7)의 경우 다음 쿼리를 사용하여 이를 달성할 수 있습니다.

    으아아아

    이것은 바이올린입니다.

    여기, @pv := '19' 中指定的值应设置为您要选择其所有后代的父级的 id.

    이 방법은 부모에게 자녀가 여러 명 있는 경우에도 적용됩니다. 그러나 각 레코드는 parent_id < 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+, DB2, Oracle 11gR2+, SQLite 3.8.4+ , 파이어버드 2.1 +, H2, HyperSQL 2.1.0+, Teradata, MariaDB 10.2.2+). 버전 8.0부터 MySQL도 이를 지원합니다. 사용할 구문은 이 답변의 상단을 참조하세요.

    일부 데이터베이스에는 Oracle, DB2, Informix과 같은 계층적 조회를 위한 대체 비표준 구문이 있습니다. CUBRID 및 기타 데이터베이스

    .

    MySQL 버전 5.7은 이러한 기능을 제공하지 않습니다. 데이터베이스 엔진이 이 구문을 제공하거나 이 구문을 제공하는 데이터베이스 엔진으로 마이그레이션할 수 있는 경우 이는 의심할 여지 없이 최선의 선택입니다. 그렇지 않은 경우 다음 대안을 고려하십시오.

    대안 2: 경로 스타일 식별자

    계층적 정보(경로)가 포함된 id 값을 지정하면 작업이 훨씬 쉬워집니다. 예를 들어, 귀하의 경우 다음과 같을 수 있습니다:

  • 취소회신하다