2012-02-29 10 views
6

Estoy construyendo un sistema de respuesta de comentarios anidados dentro de mi aplicación.Cómo combinar estas consultas MySQL y luego acceder a los datos correctamente

Actualmente todo funciona según lo previsto, sin embargo, he tenido que usar varias consultas MySQL para recuperar los datos necesarios. Y lo que es peor, la consulta para las 'respuestas' está dentro de un ciclo foreach. Lo que significa que, aunque funciona de manera admirable por ahora, está lejos de ser óptimo y causará problemas a medida que crezca el conjunto de datos.

Por lo tanto, deseo resolver esto antes de profundizar en el desarrollo.

Dado que las tablas de la aplicación comparten lo mismo que el blog de wordpress para el sitio, estoy usando la abreviatura de wordpress para las consultas.

La forma actual se genera la página es el siguiente:

Una mesa de comentarios se consulta y todos los resultados relativos a un projectId se recuperan: -

$commentquery = "select projects_comments.*, users.user_url, users.display_name 
       from ".$wpdb->prefix."projects_comments projects_comments 
       left join ".$wpdb->prefix."users users on users.ID=projects_comments.userid 
       where projectid = '$projectid' 
       order by projects_comments.commentid desc 
       "; 

$comments = $wpdb->get_results($commentquery); 

entonces realizar un bucle foreach de la siguiente : -

if($comments) { 
      foreach ($comments as $c) 
       { 


       $replyquery = "select project_replies.*, users.user_url, users.display_name 

       from ".$wpdb->prefix."project_replies project_replies 
       left join ".$wpdb->prefix."users users on users.ID=project_replies.uid 
       where project_replies.cid = '$c->commentid' 
       order by project_replies.id desc   
       limit 2   
       ";  

       $replies = $wpdb->get_results($replyquery); 

       asort($replies); 

       $countquery = "select count(*) 

        from ".$wpdb->prefix."project_replies project_replies 
        where project_replies.cid='".$c->commentid."' 
        "; 

       $replycount = $wpdb->get_var($countquery); 

    //generate html here 
    } 
} 

Dentro de este bucle hay otras dos consultas. El primero obtiene las respuestas para cada comentario pero limita los resultados a 2 (deseo hacer esto para tener un botón "ver todas las respuestas" que luego pregunta al DB por el resto si el usuario lo requiere), la segunda consulta cuenta el número total de respuestas.

El html es entonces también genera para cada respuesta dentro del bucle utilizando un segundo foreach anidado dentro del bucle anterior (donde dice generar código HTML aquí) como a continuación: -

if ($replies){ 

    foreach ($replies as $r){ 

    // generate each reply 
    } 
} 

Todos los datos se extrae de estas matrices de la siguiente manera:

$c->userid, $c->body etc... For the comments 
$r->userid, $r->body etc... For the replies. 

Deseo mantener este formato si es posible.

Como dije al principio de la pregunta, todo esto funciona a la perfección; sin embargo, soy consciente de que al anidar las consultas de conteo y conteo, realizo muchas más consultas de las necesarias. 100 comentarios generarán 100 consultas de respuestas y 100 consultas de conteos, etc.

Gracias a algunas personas útiles en este sitio, he considerado utilizar una unión para obtener todos los datos originales de una sola vez para los comentarios y respuestas. Al igual que ...

$commentquery2 = "SELECT c.commentid, c.userid, c.body as cbody, c.projectid, c.posttime, cu.user_url AS cu_url, cu.display_name AS cu_name, 
        r.*, ru.user_url AS ru_url, ru.display_name AS ru_name 
       FROM ".$wpdb->prefix."projects_comments AS c 
       LEFT JOIN ".$wpdb->prefix."users  AS cu ON cu.ID = c.userid 
       LEFT JOIN ".$wpdb->prefix."project_replies AS r ON r.cid = c.commentid 
       LEFT JOIN ".$wpdb->prefix."users  AS ru ON ru.ID = r.uid 
       WHERE c.projectid = $projectid 
       ORDER BY c.commentid DESC, r.id DESC"; 

Aunque esto en realidad funciona (y fue suficiente para mí para marcar esa pregunta como respondida), cuando se lo ponga en práctica he tenido varias dificultades.

Primero, recupero todos los datos como filas separadas, lo que significa que si tengo 5 comentarios cada uno con 3 respuestas, realmente obtengo 15 filas y no un objeto de datos anidado con las respuestas anidadas dentro de cada fila de comentario.

Para hacer frente a este he intentado alguna manipulación matriz como se muestra:

$old_id=NULL; 
$comments=array(); 

foreach($getcomments as $c){ 

    if($c->commentid !== $old_id){ 

     $comments[$old_id] = $c; 
     $old_id = $c->commentid; 

    } 


    $comments[$old_id]['replies'][] = $c; 


} 

Hacer esto me da un objeto de datos anidada según sea necesario.Sin embargo, no incluye la consulta de recuento de respuestas y no limita cada conjunto de respuestas a 2 según lo previsto, sino que recupera todas.

Y, finalmente, con mi código html generación actual dentro de los foreach:

foreach($comments){ 

    //generate comment html 

    foreach($replies) { 

     //generate replies html 

    } 

} 

Me parece que no puede conseguir que funcione correctamente con el objeto de datos anidada. Acceder a las respuestas correctas profundas parece desconcertarme.

Para resumir, deseo poder eliminar las consultas en bucle, combinarlas en una consulta grande y más eficiente o, en el peor de los casos, en una consulta de datos y una consulta de conteo separada, luego crear un objeto de datos cuidadosamente anidado. con los comentarios como filas y las respuestas anidadas dentro del encabezado 'respuestas'

Luego necesito poder iterar a través de estos correctamente dentro de mi código php para generar el html requerido.

Me disculpo por la longitud de esta pregunta y me doy cuenta de que bien podría dejar sin respuesta a muchos de ustedes, pero he estado batallando con esto durante 19 horas seguidas y realmente necesito la ayuda.

Muchas gracias a cualquiera que ofrezca alguna sugerencia.

+0

Probablemente sólo añadir sus tablas con datos de ejemplo y la tabla resultante se están esperando para conseguir que debería haber sido más útil. –

+0

Muy posiblemente Mosty, punto tomado. Si no tuviera tanta prisa ya que tengo una unidad de 2 horas antes de comenzar 10 minutos, podría editar la pregunta como sugirió. – gordyr

+0

Esto ha sido cubierto varias veces, incluyendo este artículo: http://stackoverflow.com/questions/317322/optimized-sql-for-tree-structures – crafter

Respuesta

2

Si te gusta mantener los comentarios y respuestas en dos tablas diferentes (ver el comentario de Crafter), puede eliminar el bucle con un sencillo truco: Recoger los ID de comentario de la primera consulta y utilizar un

DONDE (cid IN (1,2,3,4, ...))

en lugar del bucle. Si necesita limitar las respuestas por comentario, eso debería ser posible con cláusulas WHERE o HAVING adicionales.

BurninLeo

+0

Gracias BurninLeo. Si bien esto me ha ayudado mucho para comenzar, me gustaría dejar la pregunta abierta un poco más para poder obtener algunas respuestas/soluciones. Espero que entiendas. – gordyr

+0

Ni siquiera estoy seguro de si esto es realmente lo que necesita;) También estoy interesado en otras opiniones. Tan pronto como encuentre algo de tiempo, también leeré la introducción a los conjuntos anidados enlazados en el hilo vinculado en los comentarios a su pregunta ... – BurninLeo

Cuestiones relacionadas