2012-03-28 13 views
5

Ich baue eine App in Symfony 1.4 und Doctrine 1.2 ORM. Ich bin ziemlich neu in der Doktrin ORM und habe den Dreh raus, aber ich kann dieses Problem nicht lösen.Symfony Doctrine Abfrage zum Berechnen des Rangs nach einer Gruppe durch Unterabfrage

Ich habe eine Tabelle mit Benutzerbewertungen (mbScoreByGenre), wobei eine Benutzer-ID mehrere Datensätze von Benutzerbewertungen für ein parent_genre haben kann. dh - viele zu viele

Mein Ziel ist es, den Rang eines bestimmten Benutzers basierend auf seinen kumulativen Scores für eine gegebene parent_genre_id und user_id zu finden. Mein Ranking-Algorithmus verwendet eine Unterabfrage und ich habe eine Menge Probleme beim Erstellen einer Doktrin-Abfrage, die funktioniert.

Hier ist meine Lehre Schema für 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. Zuerst habe ich versucht, so etwas zu tun:

$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. Also änderte ich und versuchte, einen anderen Ansatz

$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 
    )'); 

Aber ich habe diesen Fehler: Alle ausgewählten Felder in Sql-Abfrage müssen im Format tableAlias.fieldName sein. Der Grund, warum ich eine Doctrine_RawSql verwendet habe, ist, dass ich lese, dass Doktrin 1.2 Unterabfragen in der Von nicht unterstützt. Bei diesem Ansatz konnte ich nicht herausfinden, wie die Spalte "total_score" im Format tableAlias.fieldName referenziert werden soll. Muss ich eine leere Komponente hinzufügen, die auf die für "total_score" zurückgegebene Unterabfragetabelle verweist?

C. Schließlich versuchte ich nur, die Unterabfrage als eine Doktrinabfrage auszuführen und den Rang zu berechnen, indem ich die Doktrinobjektzeilen zählte, die von der Abfrage zurückgegeben wurden.

$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(); 

Aber es gibt mir den Fehler:

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?

ich eine Tonne Scheuern im Internet nach Antworten gemacht habe, aber ich kann keine Antworten für jede der drei Ansätze zu finden scheinen.

Jede Hilfe wäre großartig. Bin dankbar.

+0

51 Ansichten und keine Antworten? Kann ich etwas tun, um die Frage klarer zu machen? Jede Hilfe würde sehr geschätzt werden. – frankp221

Antwort

2

Vielleicht habe ich nicht ganz verstanden, was Sie wirklich brauchen, aber haben Sie versucht, HAVING-Klausel? Die WHERE-Klausel unterstützt keine Aggregatfunktionen wie SUM(). Ich habe versucht, diesen Code und es funktionierte und kehrte einige Werte, aber ich kann nicht sicher sagen, ob dies ist, was Sie brauchen:

$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); 

Wenn dies nicht der Fall ist, was Sie brauchen - versuchen, genauer zu erklären.

+0

Vielen Dank starl1ng, das Problem war, dass WHERE Aggregatfunktionen nicht unterstützt. Ich musste auch die groupBy vor die where-Klausel setzen. Die resultierende Tabelle enthält eine Liste aller Datensätze, die der aktuellen Benutzer-ID voraus sind. Um das Ranking zu erhalten, zähle ich nur die Zeilen und füge 1 hinzu. Nochmals vielen Dank. – frankp221

0

Sie sollten Unterabfragen nicht in wo Bedingungen (oder in Ihrem Fall) mit Raw sql verschachteln. Verwenden Sie stattdessen createSubquery(), um die Doktrin explizit über die Unterabfrage zu informieren. Dies wird Ihnen auch in komplexeren Szenarien helfen, in denen die Doktrin nicht mehr tief verschachtelte rohe SQL-Abfragen verarbeiten kann.So Ihre Abfrage sollte wie folgt aussehen:

$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().")"); 

Ein weiteres Beispiel finden Sie hier:

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

Verwandte Themen