El titulo del post quizas no sea muy descriptivo, pero el problema es peliagudo, en un blog queremos saber como se podria hacer para escojer de los ultimos post aquellos en los que se haya comentado, escojer los 5 ultimos, y de cada uno de estos 5 ultimos, sacar los ids y los nombres de los ultimos 3 comentadores. ahi es nada.
La estructura de las tablas es la siguiente:
posts |
---|
id |
titulo |
comentarios |
---|
id |
post_id |
autor |
texto |
Por supuesto esto tiene una solucion facil, haces una seleccion de los ultimos comentarios y escojes los 5 ultimos que esten asociados a posts con un distinto en la consulta:
SELECT titulo, id FROM posts p, (SELECT DISTINCT (post_id) FROM comentarios ORDER BY id DESC LIMIT 5) c WHERE p.id = c.post_id
De donde sacas los ids de los ultimos posts y sus titulos, despues de esto con cada uno de los ids puedes sacar los nombres de los ultimos comentadores de cada post, introducimos en un bucle esta consulta:
SELECT id, autor FROM comentarios WHERE post_id = "( id del post actual )" ORDER BY id DESC
con lo que ya tenemos todos los datos, pero hemos necesitado 6 consultas, y para remediarlo ... tendremos que utilizar una cosilla que me encanta de mysql las variables. Sin olvidarnos de los condicionales.
En principio la solucion que habia pensado no se parece en casi nada a la final como suele ocurrir.
Primer intento:
SELECT titulo,@a:=p.id, (SELECT GROUP_CONCAT( CONCAT( c2.id,';',c2.autor)) as nick_concatenado FROM (SELECT id, autor, post_id FROM comentarios WHERE post_id =@a ORDER BY id DESC LIMIT 3) c2 GROUP BY c2.post_id HAVING c2.post_id=@a LIMIT 1) c2 WHERE c.id=c2.id) as nicks FROM posts p, (SELECT DISTINCT (post_id) FROM comentarios ORDER BY id DESC LIMIT 5) c WHERE p.id = c.post_id
la explicacion de la query ( mas bien es la explicacion de mi manera de pensar la interpretacion de la query), seleccionamos como antes los ids de los post y lo utilizamos como una tabla, a continuacion se une con la tabla de posts, por el campo id, metiendo cada id actual de la consulta (el id del post) en la variable @a hacemos una seleccion de cada uno de los comentadores limitando la consulta a 3 por post, a continuacion utilizamos la funcion GROUP_CONCAT() que devuelve separados por comas todos los registros que se agrupen por un campo. y con esto lo que pretendia obtener era algo como esto:
titulo | @a:=p.id | nicks |
---|---|---|
Titulo post 35 | 35 | 256;pepe,250;manolo,240;ana |
Titulo post 33 | 33 | 255;pepe,249;manolo,239;ana |
Titulo post 30 | 30 | 254;pepe,248;manolo,238;ana |
Titulo post 29 | 29 | 253;pepe,247;manolo,237;ana |
Titulo post 26 | 26 | 252;pepe,246;manolo,236;ana |
pero no fue asi, el problema esta en que la consulta que agrupa los ids y los nombres de los comentaristas se ejecuta antes de que @a tome valor, no porque este antes en el codigo, ya que aunque se ejecuta secuencialmente, lo que prima es el grado de anidamiento de la consulta, y esta consulta es mucho mas interior que cualquier otra.
Apartir de esto podriamos suponer que anidando la consulta llamada 'c', que contiene los ultimos 5 post_id, mas que la primera estaria solucionado, pues no!.
El siguiente problema con el que nos encontramos es que aunque la consulta se ejecute en ultimo lugar el valor que toma @a es igual al ultimo valor de la consulta 'c', en lugar de el valor de esta en cada iteracion, pero esto ultimo no se si es algo logico, o es que despues de un largo rato con esto lie tanto la consulta que me quede atrapado ahi. Fuera como fuera, el resultado es que decidi hacerlo de otra manera.
Segundo metodo
SET @cont:=-1, @post:=0; SELECT p.titulo, w.nicks, p.id FROM posts p, ( SELECT post_id, GROUP_CONCAT(CONCAT(id,';',autor)) as nicks FROM ( SELECT IF(@post=c.post_id,@cont:=@cont+1,@cont:=0) as contador, @post:=c.post_id, c.post_id, c.id, c.autor FROM comentarios c, (SELECT DISTINCT (post_id) FROM comentarios ORDER BY id DESC LIMIT 5) j WHERE c.post_id=j.post_id) k WHERE contador<3 GROUP BY post_id) w WHERE p.id=w.post_id
Este si que funciona, se basa en lo mismo que el anterior solo que variando quien controla los LIMIT, antes dejaba que mysql se encargara de ello ahora me hago mi propio metodo de LIMIT con variables e IFs. Selecciono como antes los post_id, lo uno a la tabla comentarios para que me devuelva la tabla con un campo nuevo al que he llamado contador (que es incremental), que para cada post diferente se reinicia a 0, en la siguiente subconsulta escojo solo aquellos cullo contador sea menor que 3 y con eso ya solo tengo que hacer el GROUP_CONCAT() y unir con la tabla de posts. Fin de la historia.
Perdon si es un poco lioso, pero me suelo explicar bastante mal.