mameyugo;

, 0 comentarios, 4024 lecturas, por: Jose Manuel Muras Rodrigo

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.

mysql
Unete!