2012-03-28 133 views
5

我在Symfony 1.4和Doctrine 1.2 ORM中構建了一個應用程序。我對ORM的學說非常陌生,我正在掌握它,但我無法完全解決這個問題。Symfony Doctrine按子查詢計算排名後查詢的查詢

我有一個用戶分數表(mbScoreByGenre),其中一個用戶id可以有一個parent_genre的用戶分數的多個記錄。即 - 多對多

我的目標是根據給定的parent_genre_id和user_id的累積分數找到特定用戶的排名。我的排名算法使用了一個子查詢,並且在構建可用的學說查詢時遇到了很多麻煩。

這裏是我的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 } 

答:首先我試圖做這樣的事情:

$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.於是我改變,嘗試了不同的方法

$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版的Doctrine不支持From中的子查詢。對於這種方法,我無法弄清楚如何引用tableAlias.fieldName格式中的「total_score」列。我是否必須添加一個空白組件來引用返回的「total_score」子查詢表?

C.最後,我試圖運行子查詢作爲教條查詢,並通過計算查詢返回的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?

我做了一噸精練答案的網頁,但我似乎無法找到任何的3種方法的答案。

任何幫助將是偉大的。欣賞它。

+0

51次,並沒有任何反應?我能做些什麼來使問題更清楚?任何幫助將非常感激。 – frankp221 2012-04-04 00:07:53

回答

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,問題在於WHERE不支持集合函數。我還必須在where子句之前放置groupBy。結果表格爲我提供了當前user_id之前的所有記錄的列表。要獲得排名,我只需對行進行計數並添加1.再次感謝。 – frankp221 2012-04-18 18:35:07

0

你不應該將子查詢嵌套到使用原始sql的條件(或者在你的情況下)。請使用createSubquery()明確告訴關於子查詢的原則。這也將幫助你在更復雜的情況下,教條只是不能處理深嵌套的原始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/