2012-03-28 26 views
5

Estoy compilando una aplicación en Symfony 1.4 y Doctrine 1.2 ORM. Soy bastante nuevo en la doctrina ORM y estoy aprendiendo cómo funciona, pero no puedo resolver este problema.Symfony Doctrine Consulta para calcular el rango después de un grupo por subconsulta

Tengo una tabla de puntuaciones de usuarios (mbScoreByGenre) donde una identificación de usuario puede tener múltiples registros de puntajes de usuario para un parent_genre. es decir, muchos a muchos

Mi objetivo es encontrar el rango de un usuario en particular en función de sus puntajes acumulativos para un parent_genre_id y un user_id dados. Mi algoritmo de clasificación utiliza una subconsulta y he estado teniendo muchos problemas para crear una consulta de doctrina que funcione.

Aquí es mi esquema de la doctrina de 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. Primero traté de hacer algo como esto:

$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. Entonces me cambió y trató de un enfoque diferente

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

Pero obtuve este error: todos los campos seleccionados en la consulta Sql deben estar en formato tableAlias.fieldName. El motivo por el que utilicé Doctrine_RawSql es que leo que la doctrina 1.2 no admite subconsultas en el formulario From. Para este enfoque, no pude encontrar la manera de hacer referencia a la columna "total_score" en el formato tableAlias.fieldName. ¿Tengo que agregar un componente en blanco que haga referencia a la tabla de subconsulta devuelta para "total_score"?

C. Finalmente intenté simplemente ejecutar la subconsulta como una consulta de doctrina y calcular el rango contando las filas del objeto de doctrina devuelto por la consulta.

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

Pero me da el error:

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?

He hecho un montón de fregar la web en busca de respuestas, pero me parece que no puede encontrar respuestas para cualquiera de los 3 enfoques.

Cualquier ayuda sería genial. Lo aprecio.

+0

51 puntos de vista y no hay respuestas? ¿Hay algo que pueda hacer para aclarar la pregunta? Cualquier ayuda sería muy apreciada. – frankp221

Respuesta

2

Tal vez, no entendí completamente lo que realmente necesita, pero ¿intentó cláusula HAVING? La cláusula WHERE no admite funciones agregadas como SUM(). Probé este código y funcionó y regresó algunos valores, pero no puedo decir con certeza si esto es lo que necesita:

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

Si esto no es lo que necesita - intenta explicar con mayor precisión.

+0

Muchas gracias starl1ng, el problema era que DONDE no es compatible con funciones agregadas. También tuve que poner el groupBy antes de la cláusula where. La tabla resultante me proporciona una lista de todos los registros que están por delante del user_id actual. Para obtener el ranking, solo cuento las filas y agrego 1. Gracias de nuevo. – frankp221

0

No debe anidar subconsultas en las condiciones (o tener en su caso) utilizando sql sin formato. En su lugar, use createSubquery() para indicar explícitamente la doctrina sobre la subconsulta. Esto también lo ayudará en escenarios más complejos en los que la doctrina simplemente no puede manejar consultas SQL sql profundamente anidadas.Por lo que su consulta debe ser algo como esto:

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

Otro ejemplo se puede encontrar aquí:

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

Cuestiones relacionadas