2012-03-28 2 views
5

저는 Symfony 1.4와 Doctrine 1.2 ORM에 앱을 구축하고 있습니다. 나는 교리의 ORM에 꽤 익숙하고, 그것에 매달려 있지만이 문제를 해결할 수는 없습니다.Symfony Doctrine 하위 쿼리로 그룹 뒤의 순위를 계산하는 쿼리

나는 하나의 사용자 ID가 하나의 parent_genre에 대한 사용자 점수의 여러 레코드를 가질 수있는 사용자 점수 테이블 (mbScoreByGenre)을 가지고 있습니다. ie - many to many

내 목표는 주어진 parent_genre_id 및 user_id에 대한 누적 점수를 기반으로 특정 사용자의 순위를 찾는 것입니다. 내 순위 알고리즘은 하위 쿼리를 사용하며 작동하는 교리 쿼리를 작성하는 데 많은 어려움을 겪고 있습니다. 그럼

$q = Doctrine_Query::create() 
    ->select('((SELECT COUNT(1) AS num 
     FROM 
     (SELECT SUM(mbScoreByGenre.score) 
     WHERE SUM(mbScoreByGenre.score) > SUM(s.score) 
     AND mbScoreByGenre.parent_genre_id = '.$genre['parent_id'].' 
     AND s.parent_genre_id = '.$genre['parent_id'].' 
     GROUP BY mbScoreByGenre.user_id 
     ) + 1) AS rank') 
    ->from('mbScoreByGenre s') 
    ->where('s.user_id = ?', array($user_id)) 
    ->groupBy('s.user_id') 
    ->orderBy('rank'); 

but I got the following error Fatal error: Maximum function nesting level of '100' reached, aborting! in \lib\vendor\symfony-1.4.14\lib\plugins\sfDoctrinePlugin\lib\vendor\doctrine\Doctrine\Query\Tokenizer.php on line 303. I don't understand how to build the subquery so that it works.

B. 내가 변화와 다른 접근 방식을 시도 : 여기

이 mbScoreByGenre 내 교리 스키마입니다

mbScoreByGenre: 
    actAs: 
    Timestampable: ~  
    columns: 

    id:     { type: integer, primary: true, autoincrement: true } 
    user_id:   { type: integer, notnull: true } 
    genre_id:   { type: integer, notnull: true } 
    parent_genre_id: { type: integer, notnull: true } 
    score:    { type: float, notnull: true, default: 0 } 

A. 우선 이런 식으로 뭔가를 시도

$q = new Doctrine_RawSql(); 
$q ->addComponent('s', 'mbScoreByGenre') 
    ->select('COUNT({*}) AS {rank}') 
    ->from('(SELECT SUM(s.score) AS total_score 
     FROM mb_score_by_genre s 
     WHERE s.parent_genre_id = '.$genre['parent_id'].' 
     GROUP BY s.user_id) 
      ') 
    ->where('total_score >= (
     SELECT SUM(s.score) 
     FROM mb_score_by_genre s 
     WHERE s.parent_genre_id = '.$genre['parent_id'].' 
     AND s.user_id = '.$user_id.' 
     GROUP BY s.user_id 
    )'); 

하지만 난이 오류가있어 : SQL 쿼리에서 선택한 모든 필드는 tableAlias.fieldName 형식이어야합니다. 내가 Doctrine_RawSql을 사용한 이유는 교리 문 1.2가 From에서 하위 쿼리를 지원하지 않는다는 것을 읽었 기 때문입니다. 이 접근법에서는 tableAlias.fieldName 형식의 "total_score"열을 참조하는 방법을 알 수 없습니다. "total_score"에 대해 반환 된 하위 쿼리 테이블을 참조하는 빈 구성 요소를 추가해야합니까?

C. 마지막으로 doctrine 쿼리로 하위 쿼리를 실행하고 쿼리에서 반환 한 doctrine 개체 행을 계산하여 순위를 계산했습니다.

$q = Doctrine_Query::create() 
    ->select('SUM(s.score)') 
    ->from('mbScoreByGenre s') 
    ->where('s.parent_genre_id = ?', $genre['parent_id']) 
    ->andWhere('SUM(s.score) > (
     SELECT SUM(p.score) 
     FROM mbScoreByGenre p 
     WHERE p.parent_genre_id = '.$genre['parent_id'].' 
     AND p.user_id = '.$user_id.' 
     GROUP BY p.user_id 
    )') 
    ->groupBy('s.user_id'); 

    $result = $q->execute(); 

그러나 그것은 나에게 오류 제공 :

SQLSTATE[HY000]: General error: 1111 Invalid use of group function. Is it because groupBy('s.user_id') and GROUP BY p.user_id, both p and s refer to the same model?

내가 답변을 웹 수색의 톤을 했어하지만 난 세 방법 중 하나에 대한 해답을 찾을 수없는 것입니다.

도움이 될 것입니다. 고맙습니다.

+0

(51 개)보기와 응답이없는 그래서 쿼리는 다음과 같이 보일 것이다? 질문을 더 분명하게하기 위해 할 수있는 일이 있습니까? 어떤 도움이라도 대단히 감사 할 것입니다. – frankp221

답변

2

어쩌면 내가 정말로 필요한 것을 완전히 이해하지 못했지만 HAVING 절을 시도 했습니까? WHERE 절은 SUM()과 같은 집계 함수를 지원하지 않습니다. 이 코드를 시도하고 근무하고 일부 값을 반환, 그러나 이것은 당신이 필요이면 내가 확실히 말할 수 없습니다

$q = Doctrine_Query::create() 
    ->select('count(*)') 
    ->from('mbScoreByGenre s') 
    ->where('s.parent_genre_id = ?', $genre['parent_id']) 
    ->having("SUM(s.score) > (
    SELECT SUM(p.score) 
    FROM mbScoreByGenre p 
    WHERE p.parent_genre_id = {$genre['parent_id']} 
     AND p.user_id = {$user_id})") 
->groupBy('s.user_id'); 

$result = $q->execute(array(), Doctrine::HYDRATE_SCALAR); 
var_dump($result); 

이 당신이 필요하지 않은 경우 -보다 정확한 설명하려고합니다.

+0

고맙습니다 starl1ng, 문제는 집계 함수를 지원하지 않는다는 것입니다. 나는 또한 whereByBy를 where 절 앞에 두어야 만했다. 결과 테이블은 현재 user_id보다 앞서있는 모든 레코드 목록을 제공합니다. 랭킹을 얻으려면, 행을 세고 1을 더합니다. 다시 한번 감사드립니다. – frankp221

0

원시 SQL을 사용하여 조건 (또는 경우에 따라)을 하위 쿼리에 중첩하지 마십시오. 대신 createSubquery()을 사용하여 하위 쿼리에 대해 doctrine에 명시 적으로 알리십시오. 이것은 또한 교리가 깊이 중첩 된 원시 SQL 쿼리를 더 이상 처리 할 수없는보다 복잡한 시나리오에서 도움이 될 것입니다.또 다른 예는 여기에서 찾을 수 있습니다

$q = Doctrine_Query::create() 
    ->select('count(*)') 
    ->from('mbScoreByGenre s') 
    ->where('s.parent_genre_id = ?', $genre['parent_id']) 
    ->groupBy('s.user_id') 
; 

$subquery = $q->createSubquery() 
    ->select("SUM(p.score)") 
    ->from("FROM mbScoreByGenre p") 
    ->where("p.parent_genre_id = ?", $genre['parent_id']) 
    ->andWhere("p.user_id = ?", $user_id) 
; 

$q->having("SUM(s.score) > (".$subquery->getDql().")"); 

:

http://www.philipphoffmann.de/2012/08/taming-doctrine-subqueries/