2009-11-30 3 views
2

우리 프로젝트에서 스레드 된 코멘트를 처리하는 것에 관한 결정에 직면했습니다 ... 나는 모든 코멘트를 담고있는 간단한 MySQL 테이블을 가지고 있습니다. 부모와 자녀의 두 가지 유형이 있습니다. 차일 즈는 학부모 또는 다른 아동에게 보내는 회신을 나타냅니다.MySQL 쿼리의 조건부 제한이 있습니까?

내 문제 :

-Comment (깊이 0)
- 회신 아이 (깊이 1)
--- 이전의 아이에게 회신 (깊이 2)
-Comment (깊이 0)

위의 구조와 LIMIT 2를 가진 MySQL 쿼리를 상상해보십시오. 마지막 응답 (깊이 2)을 줄일 것입니다. 사실 저는 다음과 같이 말하고 싶습니다 : 2로 제한하려고 시도하십시오.

내가 지금 뒤에대로 무엇 ... 행운과 함께 몇 가지 질의를 시도 :
이 의견 FROM SQL_CALC_FOUND_ROWS * 을 선택 comment_post_id = '{$ _REQUEST [ "ID"]}' comment_id BY ORDER, COMMENT_DATE DESC LIMIT 10 "

중요한 테이블 필드는 다음과 같습니다
comment_id (인덱스) | comment_parent_id는 (부모 또는 NULL의 comment_id을 포함) | comment_ 날짜

나는 어떤 아이디어라도 매우 감사 할 것입니다!

Saludos, Booosh

+0

네, 일부 스키마와 SQL 정보가 도움이 될 것입니다. –

+0

'LIMIT 2 '는 쿼리가 2 행만 반환한다는 것을 의미합니다. 나는 너를 모으고 있는데, 아이들이 2 명 밖에 안가는 명단을 돌려주고 싶니? –

+0

예 ... 정확합니다. 중요한 테이블 구조체 : comment_id | parent_coment id | SQL 쿼리를 COMMENT_DATE : SQL_CALC_FOUND_ROWS * 의견 FROM WHERE comment_post_id = '{$ _REQUEST [ "ID"]}' ORDER comment_id, COMMENT_DATE 통해 선택 DESC 제한하는 10 – Bosh

답변

1

MySQL은 나무와 같은 구조를 구문 분석 할 수있는 기능을 가지고 있지 않습니다. 가장 간단한 시나리오 (자식이 부모의 ID를 가짐)에서는 주어진 노드의 모든 하위 노드를 찾기 위해 프로그래밍 방식으로 트리를 반복해야합니다. MaxLevel은 원하는 깊이를 나타냅니다. 그것은 각각의 재귀 호출이 감소하기 때문에 결국에는 재귀를 멈추는 0으로 끝납니다.

(의사 코드)

findNodes(String parentId, int maxLevel) 
{ 
    select * from posts where parent = parentId 
    foreach (result...) 
    { 
    if (maxLevel > 0) 
    { 
     findNodes(result.nodeId, maxLevel - 1) 
    } 
    doSomethingWIthAResult 
    } 
} 

더 간결한 방법으로이 작업을 수행하기 위해, 현재 게시물에 대한 경로를 포함하는 인덱스 필드의 일종을 포함 모두 기술의 숫자가 있습니다. 경로는 다음과 같이 보일 수 있습니다. TopNode : Child1 : Child2 : Child3 ...이 중에서 선택할 수있는 위치 "TopNode %"및 깊이 = 2와 같은 경로에서 * 선택하십시오.

+0

헤이 들으 대답 ..하지만 실제로 나에게 꽤 분명하고 비슷한 형식의 함수를 이미 내 의견을 주문 ... 어쩌면 내가 완전히 틀린하지만 피하고 싶지 한 번에 모든 의견을 가져 오는 것입니다. 하지만 부모의 모든 자식이 가져온다는 것을 확신하십시오 ... 하위 쿼리가 다소 해결책 일 수 있다고 생각합니다 ... 모든 부모를 얻는 것과 비슷한 것, 10으로 제한하고 모든 자식을 가져 오는 것 ... – Bosh

+0

그냥 파기 할 필요가 있습니다. 조금 더 mySQL의 documnetation에 ... 어쩌면 내가 뭔가를 찾을거야 – Bosh

1

항상 생각하십시오. 당신이 정말로 데이터베이스에 물어보고 싶은 질문에 대해서는 다음에을 SQL로 번역하십시오.이 경우에는 "직접 자식이있는 모든 최상위 주석의 목록"이 필요합니다.

예 : c2.comment_id가 null의 경우, 그것은 자녀가없는 최고 수준의 코멘트, 그리고 c1.comment_id이 반복되면, 그건 - 그 결과로

SELECT * FROM comments c1 
LEFT JOIN comments c2 ON c2.parent_comment_id=c1.comment_id 
WHERE c1.parent_comment_id IS NULL 
ORDER BY c1.comment_date, c1.comment_id, c2.comment_date, c2.comment_id; 

, 당신은 올바른 순서로 그들을 밖으로 쓸 수 (간체) 같은 코멘트의 다른 아이.

+0

Uhmm, 이것은 내가 enlightment 전화 ... Didnt 내가 하나의 자체 테이블에 가입 할 수 있다는 것을 알고 ... 와우 ;-) 난 이것이 내 한계 문제를 해결할 지 모르겠지만 그 시도를 할 것입니다;) 감사합니다. 아주 많이 !!! – Bosh

0

나는 그럭저럭 그럭저럭 그럭저럭 Adamskis 힌트에 의거하여 를 관리 할 수 ​​있었다. .. 그래서 나의 대답을 투표하지 마라. 그러나 그의 하나를 조사해라! !!

짧은 문제를 설명하려면 ... 우리 웹 사이트의 의견 목록에 대한 페이지 매김이 필요합니다. 표준 제한을 사용하면 일부 댓글이 표시되지 않을 수도 있습니다 ... 우리가 필요로했던 것은 부모 노드에만 영향을 미치는 제한 이었지만 응답 인 어린이 노드는 아닙니다 ... 긴 이야기 ... 그러나 한 번만해도 유용합니다. 누군가를 위해 :

function getComments($comment_parent_id, $scope,&$comments, $db) 
    { 
     $res = $db->select("SELECT * FROM comments WHERE comment_post_id = '{$_REQUEST["ID"]}' AND comment_parent_id = '{$comment_parent_id}' ORDER BY comment_date DESC LIMIT {$scope}"); 

     while ($row = mysql_fetch_array($res, MYSQL_ASSOC)) 
     { 
      $i = count($comments)+1; 

      foreach ($row as $k => $v) { 
       $comments[$i][$k] = $v; 
      } 

      //LOOK FOR REPLIES (childs of parent) 
      if (mysql_num_rows($db->select("SELECT * FROM comments WHERE comment_parent_id = '{$row['comment_id']}' LIMIT 1")) != 0){ 
       getComments($row['comment_id'],100,$comments,$db); 
      } 
     } 
    } 

    //ARGUMENTS: parent_id (always starting with zero), scope, array holding comments, db class 
    getComments(0,5,$comments,$db); 
1

저는이 같은 문제에 직면했습니다.

    : 만 10

    SELECT c.* FROM comments AS c WHERE c.OwnerId = 1 AND c.ParentId = 0 LIMIT 10 
    UNION 
    SELECT cc.* FROM comments AS cc 
        INNER JOIN 
        (
         SELECT CommentId FROM comments WHERE OwnerId = 1 AND ParentId = 0 LIMIT 10 
        ) 
        AS c2 
        ON cc.ParentId = c2.CommentId 
    

    이 쿼리에 상위 레벨 Comment 기록을 제한하면서

    --Comment (depth: 0) 
    ---Reply (depth: 1) 
    

    나는 기본적으로 다음과 같은 작업을 수행, 모든 레코드를 선택하는 단일 쿼리를 사용하여 관리

  • 최상위 레벨 주석 인 처음 10 개의 레코드를 가져오고 특정 소유자 ID가 있습니다.
  • 첫 번째 쿼리에서 이 반환 된 주석 ID와 동일한 상위 ID를 가진 모든 주석을 가져 와서 결과 집합에 결합합니다.

이 쿼리는 각 레코드에 대해 데이터베이스를 여러 번 호출하는 것보다 효율적이라고 생각하지만 여전히 첫 번째 쿼리를 두 번 실행한다는 결함이 있습니다. 노동 조합 전에 한 번, 노동 조합에 한 번.

꽤 빠르지 만 빠른 것만은 아닙니다. 그러나 데이터베이스가 원격이고 대기 시간이 문제가되는 경우이 솔루션은 데이터베이스에 대한 여러 원격 쿼리를 작성하는 것보다 나을 수도 있습니다.

+0

귀하의 예가이 똑같은 문제를 해결하는 데 도움이되었습니다.INNER JOIN을 닫은 후에도 조건을 UNION Select에 추가했지만이를 변경해야했습니다. –