재귀 자기 조인


15

나는 comments이것을 단순화 할 수 있는 테이블을 가지고 있다 :

comments
=======
id
user_id
text
parent_id

여기서 parent_idnull은 허용되지만 상위 주석의 키일 수 있습니다.


이제 select특정 의견의 모든 후손을 어떻게 할 수 있습니까?
댓글이 여러 수준 아래로 떨어질 수 있습니다 ...

답변:


16

재귀 쿼리가 알려진 계층 적 쿼리는 MySQL에서 지원되지 않습니다.

그러나 Oracle, Microsoft SQL Server, DB2 및 PostgreSQL에서 지원됩니다.

해결 방법이 필요한 경우 /programming/8104187/mysql-hierarchical-queries 에서 역동적이고 잠재적으로 위험한 트릭을 찾을 수 있습니다.

당신은 또한보다 다른 모델과 계층 적 데이터를 저장하는 방법에 대한 토론을 찾을 수 인접성 (adjacency) 목록 (즉, 부모 여기 열) : /programming/192220/what-is-the-most-efficient- 우아한 길을 파싱 평면 테이블 나무로 /

행운을 빕니다!


두 번째 링크의 솔루션이 어떻게 위험한지 궁금합니다. 설명해 주시겠습니까? 그렇지 않으면 사이트에 오신 것을 환영합니다!
dezso

3
@dezso : 쿼리 자체의 제작자 인 Quassnoi는 " MySQL은 세션 변수 동작을 명확하게 정의하지 않기 때문에 업그레이드 안전하지 않습니다 *. 그러나 쿼리 내에서 인접 목록을 적시에 처리 할 수있는 유일한 방법 입니다." 위험한 단어가 너무 강했을 수 있지만 ( 잠재적으로 불안정한 가요?)주의 측면에서 실수하는 것을 선호합니다 (또한 MySQL보다 Oracle에 대해 더 잘 알고 있기 때문에 매우 조심하고 싶었습니다). 그건 그렇고, 환영합니다! 나는 SE 네트워크에 오랜 시간을 투자 해 왔으며, 약간을 상환 할 시간이라고 결정했다.
Valmoer

2
WITH [RECURSIVE] 구문은 이제 mysql 8.0에서 지원됩니다. dev.mysql.com/doc/refman/8.0/en/with.html
ClearCrescendo

6

이 테이블 디자인은 Bill Karwin ( SQL Antipatterns Strike Back 프레젠테이션의 슬라이드 48에서 시작)에 설명 된대로 SQL 반 패턴 "순진한 나무" 입니다. 이 디자인의 문제는 특히 노드의 모든 자손 (또는 부모)을 얻는 데 어려움이 있다는 것입니다. MySQL을 사용하고 있으므로 다른 RDBMS에있는 공통 테이블 표현식 (with 문 및 RECURSIVE 수정 자)을 사용할 수 없습니다.

당신이 남은 것은 :

  • 계층 적 데이터 구조의 대체 구현 사용 ( 이 질문에 대한 답변은 이에 대한 좋은 참조 일 수 있음)
  • 깊이 제한으로 자체 조인 쿼리를 작성하십시오. 깊이 = 5의 경우 다음 줄에 무언가를 사용할 수 있습니다.

    SELECT *
    FROM comments AS c1
      JOIN comments AS c2 ON (c2.parent_id = c1.id)
      JOIN comments AS c3 ON (c3.parent_id = c2.id)
      JOIN comments AS c4 ON (c4.parent_id = c3.id)
      JOIN comments AS c5 ON (c5.parent_id = c4.id)
  • WITH RECURSIVE를 지원하는 RDBMS를 사용하십시오 (대부분의 사람들에게는 이것이 옵션이 아닐 수도 있음)


2
Bill Karwin에 동의하지 않습니다. 인접 모델은 반 패턴 이 아닙니다 . 재귀 쿼리를 지원하는 최신 DBMS (Oracle은 20 년 이상 지원)를 통해 이러한 모델을 검색 하고 업데이트하는 데 매우 효율적 입니다.
a_horse_with_no_name

5

MySQL은 필요한 쿼리와 같은 재귀 쿼리를 지원하지 않습니다.

내가 얼마 전에했던 것은 그렇게하기위한 모델을 제공하는 저장 프로 시저를 작성하는 것이 었습니다.

바퀴를 재발 명하기보다는, 과거의 게시물에 대한 링크를 제공합니다.

요컨대, 내가 만든 저장 프로 시저는 대기열 처리를 사용하여 트리를 사전 주문합니다.

  • GetParentIDByID
  • GetAncestry
  • GetFamilyTree

모든 자녀의 부모 (예 : GetFamilyTree 저장 프로 시저)

  • STEP01) parent_id대기열에서 시작
  • STEP02) 다음 parent_id전류를 대기열에서 제외
  • STEP03) id현재의 모든 값을 큐에 넣습니다parent_id
  • STEP04) 코멘트 인쇄 또는 수집
  • STEP05) 대기열이 비어 있지 않으면 STEP02
  • STEP06) 끝났습니다 !!!

모든 부모의 자녀 (예 : GetAncestry 저장 프로 시저)

  • STEP01) id대기열에서 시작
  • STEP02) 다음 id전류를 대기열에서 제외
  • STEP03) parent_id전류 값을 큐에 넣는다id
  • STEP04) 코멘트 인쇄 또는 수집
  • STEP05) 대기열이 비어 있지 않으면 STEP02
  • STEP06) 끝났습니다 !!!

구현 내용을 보려면 다른 게시물의 저장 프로 시저를 살펴보십시오.

시도 해봐 !!!


2
SELECT  group_concat(@id :=
        (
        SELECT  id
        FROM    comments
        WHERE   parent_id = @id
        )) AS comment
FROM    (
        SELECT  @id := 1
        ) vars
STRAIGHT_JOIN
        comments
WHERE   @id IS NOT NULL

깡깡이

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.