programing

MySQL의 트리 구조 테이블을 한 번에 조회할 수 있습니까?

bestcode 2022. 10. 18. 22:52
반응형

MySQL의 트리 구조 테이블을 한 번에 조회할 수 있습니까?

대답은 아니라고 생각합니다만, SQL(MySQL)에서 트리 구조를 어느 정도 크롤링하는 방법에 대한 통찰력이 있으면 좋겠습니다만, 단 한 번의 쿼리로도 충분합니다.

구체적으로는 트리 구조화 테이블(id, data, data, parent_id)과 테이블 내의 1개의 행이 주어지면 모든 하위(자녀/손자녀 등)를 취득할 수 있습니까?또, 그 점에 대해서는, 1개의 쿼리를 사용해 얼마나 다운 또는 업이 되는지를 모르는 채로, 모든 상위(부모/조부모/조부모 등)를 취득할 수 있습니까?

아니면 새로운 결과가 나오지 않을 때까지 더 깊은 쿼리를 계속해야 하는 재귀가 필요할까요?

구체적으로는 Ruby and Rails를 사용하고 있습니다만, 그다지 관련이 없는 것 같습니다.

예, 가능합니다. 여기서 가장 잘 설명한 대로 수정된 사전 주문 트리 트래버설입니다.

Smarties용 SQL에서의 Joe Celko의 트리와 계층

(PHP의) 작업 예는 다음과 같습니다.

http://www.sitepoint.com/article/hierarchical-data-database/2/

다음은 몇 가지 리소스입니다.

기본적으로 저장 프로시저에서 일종의 커서를 사용하거나 인접 관계 테이블을 쿼리하거나 구축해야 합니다.db 밖에서 재귀하는 피하고 싶다.트리의 깊이에 따라서는 매우 느리거나 복잡해질 수 있다.

대니얼 비어즐리의 대답은 당신이 묻고 있는 주요 질문들이 '모든 내 자녀들은 무엇인가'와 '모든 부모님들은 무엇인가'일 때 전혀 나쁜 해결책은 아니다.

Alex Weinstein에 대한 응답으로, 이 방법은 Celko 기술보다 부모 이동의 노드에 대한 업데이트가 적습니다.Celko의 기술에서는 맨 왼쪽에 있는 레벨2 노드가 맨 오른쪽에 있는 레벨1 노드 아래로 이동하면 트리의 거의 모든 노드를 업데이트해야 합니다.단, 노드의 자녀 노드뿐만 아니라.

하지만 제가 말하고 싶은 것은 다니엘이 잘못된 방향으로 뿌리를 내릴 수 있는 길을 저장했을 수도 있다는 것입니다.

저장해서 문의할 수 있도록 하겠습니다.

SELECT FROM table WHERE ancestors LIKE "1,2,6%"

즉, mysql은 '조상' 열에 있는 인덱스를 사용할 수 있으며, 선두 %로는 사용할 수 없습니다.

나는 전에 이 문제를 접한 적이 있는데 이상한 생각이 하나 들었다.레코드에 필드를 저장할 수 있습니다.각 레코드는 직계 조상 ID 문자열로 루트로 돌아갑니다.

이런 기록이 있다고 상상해 보세요(계승은 가계를 의미하고 숫자는 ID, 조상).

  • 1, "1"
    • 2, "2,1"
      • 5, "5,2,1"
      • 6, "6,2,1"
        • 7, "7,6,2,1"
        • 11, "11,6,2,1"
    • 3, "3,1"
      • 8, "8,3,1"
      • 9, "9,3,1"
      • 10, "10,3,1"

그러면 id:6의 하위 항목을 선택하려면 다음과 같이 하십시오.

SELECT FROM table WHERE ancestors LIKE "%6,2,1"

이전 컬럼을 최신 상태로 유지하는 것은 매우 번거로운 일이지만 모든 DB에서 실현 가능한 솔루션입니다.

셀코의 기술(네스트 세트)은 꽤 좋다.또, 「조상」, 「후예」, 「거리」의 필드를 가지는 인접 관계 테이블도 사용하고 있습니다(예를 들면, 직계 자녀/부모의 거리는 1, 손자/조부모의 거리는 2 등).

이것은 유지되어야 하지만 삽입의 경우 매우 간단합니다. 트랜잭션을 사용하여 직접 링크(부모, 자녀, 거리=1)를 테이블에 넣은 다음 기존 부모 및 자녀의 선택 항목을 INSERT IGNORECT(INSERT IGNORE)를 거리 추가(기회가 있을 때 SQL을 끌어올릴 수 있음)하여 성능을 위해 각 필드에 인덱스를 붙입니다.이 접근법이 더 보기 흉해지는 것은 삭제에 관한 것이다.기본적으로 영향을 받은 항목을 모두 표시한 후 다시 작성해야 합니다.그러나 이것의 장점은 내포된 집합 모델은 직선 계층 구조만 수행할 수 있는 반면 임의 비순환 그래프를 처리할 수 있다는 것이다(예: 루트를 제외한 각 항목은 한 개의 상위만 있음).

SQL은 Turing Complete 언어가 아닙니다. 즉, 이러한 종류의 루프를 수행할 수 없습니다.SQL 및 트리 구조를 사용하여 매우 현명한 작업을 수행할 수 있지만, 임의의 깊이의 계층에 대해 "계층 내" 특정 ID를 가진 행을 설명하는 방법이 생각나지 않습니다.

당신의 최선의 선택은 @Dan이 제안한 것과 같은 것입니다. 즉, 다른 보다 능력 있는 언어로 트리를 통과해 가는 것입니다.실제로 루프를 사용하여 범용 언어로 쿼리 문자열을 생성할 수 있습니다.여기서 쿼리는 찾고 있는 계층의 깊이를 반영하는 복잡한 일련의 조인(또는 하위 쿼리)일 뿐입니다.이 방법은 루핑 및 여러 쿼리보다 효율적입니다.

이것은 확실히 실행할 수 있고 SQL에 있어서도 그다지 복잡하지 않습니다.이 질문에 답변하고 mysql 프로시저 코드를 사용한 작업 예를 제시했습니다.

MySQL: 특정 노드에서 잎을 찾는 방법

부스: 만약 당신이 만족한다면, 당신은 대답 중 하나를 수락으로 표시해야 합니다.

https://stackoverflow.com/questions/27013093/recursive-query-emulation-in-mysql(https://stackoverflow.com/users/1726419/yossico) 제공)에서 설명한 "With Emulator" 루틴을 사용했습니다.지금까지 매우 좋은 결과(성능 측면)를 얻었지만, 검색해야 할 데이터나 하위 데이터가 많지 않습니다.

당신은 분명히 재귀적인 방법을 사용하길 원할 것입니다.이렇게 하면 트리 전체를 일정한 깊이로 만드는 것보다 쉽게 만들 수 있습니다.

매우 대략적인 의사 코드에서는 다음과 같은 것이 필요합니다.

getChildren(parent){
    children = query(SELECT * FROM table WHERE parent_id = parent.id)
    return children
}

printTree(root){
    print root
    children = getChildren(root)
    for child in children {
        printTree(child)
    }
}

하지만 실제로 이런 일은 거의 하고 싶지 않을 겁니다.테이블 내의 각 행에 대해 1개의 요청을 하기 때문에 다소 비효율적입니다.따라서 작은 테이블이나 너무 깊게 중첩되지 않은 트리에 대해서만 유효합니다.솔직히 말하면, 어느 경우든 깊이를 제한하고 싶을 것입니다.

그러나 이러한 종류의 데이터 구조가 널리 보급되어 있기 때문에 특히 필요한 쿼리 수를 줄이기 위해 MySQL을 사용할 수 있습니다.

편집: 생각해 본 결과, 이러한 모든 쿼리를 작성하는 것은 의미가 없습니다.표 전체를 읽고 있는 경우는, RAM에 전체를 넣을 수 있습니다.충분히 작다고 가정하면 됩니다.

언급URL : https://stackoverflow.com/questions/169817/is-it-possible-to-query-a-tree-structure-table-in-mysql-in-a-single-query-to-an

반응형