php - Doctrine Query Language obtiene Max/Latest Row por grupo
mysql symfony (4)
Estoy intentando y no puedo traducir mi declaración SQL relativamente simple en una que funcione dentro de Doctrine.
Esta es la instrucción SQL, que funciona según sea necesario cuando se ejecuta en mi base de datos:
SELECT a.*
FROM score a
INNER JOIN (
SELECT name, MAX(score) AS highest
FROM score
GROUP BY name
) b
ON a.score = b.highest AND a.name = b.name
GROUP BY name
ORDER BY b.highest DESC, a.dateCreated DESC
Aquí está el intento de DQL hasta ahora:
$kb = $em->createQuery(
"SELECT a
FROM ShmupBundle:Score a
INNER JOIN a.name ShmupBundle:Score b WITH a.score = b.score AND a.name = b.name GROUP BY b.name
WHERE a.platform=''keyboard''
GROUP BY a.name
ORDER BY b.score DESC, a.dateCreated DESC"
);
Que actualmente está dando este error:
[Semantical Error] line 0, col 73 near ''ShmupBundle:Score'': Error: Class ShmupBundle/Entity/Score has no association named name
La tabla en sí es bastante simple: id, nombre, puntaje, plataforma, fechaCreada
Hay múltiples entradas con el mismo nombre, pero con puntajes diferentes. Quiero mostrar solo el "puntaje alto" por nombre. He estado probando por un día o dos ahora, sin suerte. ¿Alguien puede señalarme en la dirección correcta?
La consulta que intenta hacer con la doctrina está relacionada con la greatest-n-per-group . Para usar una subconsulta y luego unirse con la consulta principal, las cosas son complicadas de manejar con doctrina. A continuación, se muestra la versión SQL reescrita para obtener los mismos resultados sin el uso de ninguna función agregada:
SELECT
a.*
FROM
score a
LEFT JOIN score b
ON a.name = b.name
AND a.score < b.score
WHERE b.score IS NULL
ORDER BY a.score DESC
Para convertir la consulta anterior equivalente a doctrina o DQL es fácil, a continuación se muestra la versión DQL de SQL anterior:
SELECT a
FROM AppBundle/Entity/Score a
LEFT JOIN AppBundle/Entity/Score b
WITH a.name = b.name
AND a.score < b.score
WHERE b.score IS NULL
ORDER BY a.score DESC
O con el generador de consultas puede escribir algo como lo que he probado a continuación con Symfony 2.8 usando el DEMO
$DM = $this->get( ''Doctrine'' )->getManager();
$repo = $DM->getRepository( ''AppBundle/Entity/Score'' );
$results = $repo->createQueryBuilder( ''a'' )
->select( ''a'' )
->leftJoin(
''AppBundle/Entity/Score'',
''b'',
''WITH'',
''a.name = b.name AND a.score < b.score''
)
->where( ''b.score IS NULL'' )
->orderBy( ''a.score'',''DESC'' )
->getQuery()
->getResult();
Otra idea sería crear una vista usando su consulta en la base de datos y en Symfony crear una entidad, poner el nombre de la vista en la anotación de la tabla y simplemente comenzar a llamar a su entidad, le dará los resultados devueltos por su consulta, pero este enfoque no se recomienda solo una solución temporal .
La declaración de unión interna necesita el primer argumento como tabla, que es un error semántico en su consulta.
$kb = $em->createQuery(
"SELECT a
FROM ShmupBundle:Score a
INNER JOIN ShmupBundle:Score b ON a.score = b.score AND a.name = b.name GROUP BY b.name
WHERE a.platform=''keyboard''
GROUP BY a.name
ORDER BY b.score DESC, a.dateCreated DESC");
usa esto en clase
$name = $em->getRepository(''AppBundle:BlogPost'')->getMaxId();
en el repositorio puedes usar algo como
public function getMaxId()
{
$qb = $this->createQueryBuilder(''u'');
$qb->select(''u, MAX(id) as idMax'');
return $qb->getQuery()->getSingleResult();
}
-
MySQL no entiende la sintaxis
:
Si se supone queShmupBundle:Score
es una base de datos y una tabla,ShmupBundle:Score
.
. Si se supone que Doctrine lo reemplaza con algo, ¿qué hace con él? -
Solo puede haber una cláusula
GROUP BY
, y debe estar después de la cláusulaWHERE
. Intente eliminarGROUP BY b.name
. -
No hay necesidad de
b.name
GROUP BY
b.name
ya.name
ya que son iguales.