Foros del Web » Programando para Internet » PHP »

armar consulta dinámica con múltiples parametros

Estas en el tema de armar consulta dinámica con múltiples parametros en el foro de PHP en Foros del Web. que tal forer@s!!! Estoy tratando de optimizar y mejorar una consulta dinamica que voy armando depende de las variables que me manden, espero que me ...
  #1 (permalink)  
Antiguo 29/10/2012, 20:11
Avatar de catpaw  
Fecha de Ingreso: mayo-2010
Ubicación: xalapa
Mensajes: 856
Antigüedad: 14 años, 6 meses
Puntos: 23
armar consulta dinámica con múltiples parametros

que tal forer@s!!!

Estoy tratando de optimizar y mejorar una consulta dinamica que voy armando depende de las variables que me manden, espero que me puedan aconsejar y dar su punto vista sobre mi codigo y si se puede mejorar se los agradecere.

Veran, tengo un formulario con los siguientes campos:

año: [combo de años desde 1990 a 2012]
trimestre: [combo de los 4 trimestres del año]
o Seleccione la fecha: [input con formato de fecha 2012-10-29]

después puede haber o no (uno o muchos) los siguientes combos:

Estatus: [combo con los valores, por ejemplo: en mantenimiento, acabado]
Tipo: [combo con los valores, por ejemplo: mantenimiento, soporte]
...pueden haber mas combos o uno o ninguno => los valores estos combos los meto en un arreglo, por ejemplo si tengo dos combos queda, dependiendo de la opción que elijan [1,2]

entonces mis parámetros son:

año, trimestre, fecha y arreglo de combos (en todos los campos si no son seleccionados se les pone el valor s por default)

por el momento la consulta la hago con la siguiente lógica:

Código PHP:
Ver original
  1. <?php
  2. //recibo variables
  3. $fecha = $_GET['fecha'];
  4. $anio = $_GET['anio'];
  5. $trim = $_GET['trim'];
  6. $clases = $_GET['clases']; //arreglo
  7.  
  8. $query = "select * from tabla where id='$id' and "; //esta linea siempre sera igual
  9.  
  10. if($fecha!="s"){ //si el input de fecha no esta vació
  11.    $query .= "fecha='$fecha' ";
  12. } else{
  13.     //si el usuario elige año y trimestre
  14.     if($anio!="s" && $trim!="s"){
  15.          //entonces yo armo la fecha de inicio y la fecha final en base al trimestre correspondiente
  16.          $trim = explode("/",$trim); //recibo el trimestre: mm-dd/mm-dd
  17.          $trim_ini = $trim[0];
  18.          $trim_fin = $trim[1];
  19.          $fecha_ini = $anio."-".$trim_ini;
  20.          $fecha_fin = $anio."-".$trim_fin;
  21.          //hago la condición de la consulta
  22.          $query .= "fecha between '$fecha_ini' and '$fecha_fin' ";
  23.    }
  24.    else{
  25.        //si solo eligio el año
  26.        if($anio!="s"){
  27.             $query .= "left(fecha, 4)='$anio' ";
  28.        }
  29.    }
  30. }
  31. ?>

ahora si el arreglo es diferente de s, que significa que esta vacio, a lo anterior le sumo:

Código PHP:
Ver original
  1. <?php
  2. $clase = explode(",",$clases);
  3. $NroClases = count($clase)
  4.     for($i=0;$i<$NroClases;$i++){
  5.     if($clase[$i]!="s"){
  6.         $query .= " and ";
  7.         $query .= "clase='".$clase[$i]."' ";
  8.     }
  9. }
  10.  
  11. //finalmente
  12. $query .= "order by id ASC";
  13. $rs3 = mysql_query($query) or die(mysql_error());
  14. while($row3 = mysql_fetch_array($rs3, MYSQL_ASSOC)){
  15.       //imprimo los valores
  16.       echo $row3['id'];
  17.       ....
  18. }
  19. ?>

Bueno los detalles que le veo a mi código actualmente es que la consulta forzosamente tiene que pasar por tener fecha o año para desplegar la consulta, es decir si yo quiero consultar solo los combos que forman el arreglo la consulta no se hace por que al armar el query les pongo que empiecen con "and" y entonces ya hay error en la sintaxis

me gustaría poder seleccionar primero cualquiera de la dos alternativas (año-trimestre/fecha o arreglo de combos) para que la consulta se lance sin problemas.

Tambien espero que me digan si habra mejor forma de hacer esto, o de optimizar mi codigo o de plano si es una aberración a la programacion lo que estoy haciendo

o si voy bien

bueno cabe aclarar que como lo tengo si funciona bien, salvo que me gustaria mejorar lo que ya les comente

gracias

Última edición por catpaw; 29/10/2012 a las 20:18
  #2 (permalink)  
Antiguo 30/10/2012, 17:55
Avatar de Triby
Mod on free time
 
Fecha de Ingreso: agosto-2008
Ubicación: $MX->Gto['León'];
Mensajes: 10.106
Antigüedad: 16 años, 3 meses
Puntos: 2237
Respuesta: armar consulta dinámica con múltiples parametros

Lo más fácil sería crear un arreglo con los filtros que aplicarás, ejemplo:

Código PHP:
Ver original
  1. $filtros = array();
  2. if(isset($_GET['id']) && $_GET['id'] != 0) {
  3.     $filtros[] = "id={$_GET['id']}";
  4. }
  5. if(isset($_GET['combo1']) && $_GET['combo1'] != 's') {
  6.     $filtros[] = "campo1='{$_GET['combo1']}'";
  7. }
  8. if(isset($_GET['comboN']) && $_GET['comboN'] != 's') {
  9.     $filtros[] = "campoN='{$_GET['comboN']}'";
  10. }
  11.  
  12. // Armas la consulta
  13. $sql = 'SELECT * FROM tabla';
  14.  
  15. // Si hay filtros a aplicar, los agregas:
  16. if(count($filtros) > 0) {
  17.     $sql .= ' WHERE ' . implode(' and ', $filtros);
  18. }

Sólo recuerda verificar y, en su caso, escapar cada dato recibido para evitar errores y/o posibles ataques.
__________________
- León, Guanajuato
- GV-Foto
  #3 (permalink)  
Antiguo 01/11/2012, 09:51
Avatar de catpaw  
Fecha de Ingreso: mayo-2010
Ubicación: xalapa
Mensajes: 856
Antigüedad: 14 años, 6 meses
Puntos: 23
Respuesta: armar consulta dinámica con múltiples parametros

hola triby gracias por tu respuesta y disculpa la tardanza de la mia,

Es verdad que usar filtros es lo mas recomendable como me planteas, pero el problema es que yo antes de armar la consulta tengo que validar las variables que llegan para decidir como crear la consulta, aunque me parece de maravilla como usaste el implode

pues resulta que hice algunos cambios y ya me da el resultado que esperaba, aunque sigo con mis dudas sobre la programacion, en fin hice lo siguiente:

En la primer parte hice un pequeño cambio, en lugar de concatenar en la cadena que guarda la consulta, concateno en una cadena auxiliar

Código PHP:
Ver original
  1. <?php
  2. //recibo variables
  3. $fecha = $_GET['fecha'];
  4. $anio = $_GET['anio'];
  5. $trim = $_GET['trim'];
  6. $clases = $_GET['clases']; //arreglo
  7.  
  8. $query = "select * from tabla where id='$id' and "; //esta linea siempre sera igual
  9.  
  10. $cad1 = ""; //cadena auxiliar 1
  11. if($fecha!="s"){ //si el input de fecha no esta vació
  12.    $cad1 .= "fecha='$fecha' ";
  13. } else{
  14.     //si el usuario elige año y trimestre
  15.     if($anio!="s" && $trim!="s"){
  16.          //entonces yo armo la fecha de inicio y la fecha final en base al trimestre correspondiente
  17.          $trim = explode("/",$trim); //recibo el trimestre: mm-dd/mm-dd
  18.          $trim_ini = $trim[0];
  19.          $trim_fin = $trim[1];
  20.          $fecha_ini = $anio."-".$trim_ini;
  21.          $fecha_fin = $anio."-".$trim_fin;
  22.          //hago la condición de la consulta
  23.          $cad1 .= "fecha between '$fecha_ini' and '$fecha_fin' ";
  24.    }
  25.    else{
  26.        //si solo eligio el año
  27.        if($anio!="s"){
  28.             $cad1 .= "left(fecha, 4)='$anio' ";
  29.        }
  30.    }
  31. }
  32. ?>

el problema era como armaba la segunda parte, que estaba atenida a la primera, por lo que, agregue una segunda cadena auxiliar para concatenar la parte de los arreglos:

Código PHP:
Ver original
  1. <?php
  2. $clase = explode(",",$clases);
  3.  
  4. $cad2 = ""; //cadena auxiliar 2
  5. $NroClases = count($clase); //cuantos valores trae el arreglo
  6. if($NroClases!="0"){ //si el arreglo no esta vacio
  7.     for($i=0;$i<$NroClases;$i++){
  8.         if($clase[$i]!="s"){
  9.             //concateno en la cadena auxiliar
  10.             $cad2 .= "id_".$array_clases[$i]."='".$clase[$i]."' ";
  11.             $cad2 .= "and ";
  12.         }    
  13.     }
  14.     $cad2 = substr($cad2,0, -4); //le quito el ultimo and    
  15. }
  16.  
  17. //armo la otra parte del where de la consulta dependiendo de si hay cad1 y/o cad2
  18. if($cad1!="" && $cad2!=""){
  19.     $query .= $cad1." and ".$cad2;
  20. } else{
  21.     if($cad1!="" && $cad2==""){
  22.         $query .= $cad1;
  23.     } else{
  24.         if($cad2!="" && $cad1==""){
  25.             $query .= $cad2;
  26.         }
  27.     }
  28. }
  29.  
  30. //concluyo la consulta con un order by
  31. $query .= " order by id_arch ASC";
  32.  
  33. $rs3 = mysql_query($query) or die(mysql_error());
  34. while($row3 = mysql_fetch_array($rs3, MYSQL_ASSOC)){
  35.       //imprimo los valores
  36.       echo $row3['id'];
  37.       ....
  38. }
  39. ?>

Con esos cambios ya se hace la consulta ya sea con los primeros parámetros que recibo (fecha o año y/o trimestre) o con los parámetros del arreglo

Aunque para otros casos la solución idónea debería ser como lo planteas Triby gracias
  #4 (permalink)  
Antiguo 01/11/2012, 12:25
Avatar de Triby
Mod on free time
 
Fecha de Ingreso: agosto-2008
Ubicación: $MX->Gto['León'];
Mensajes: 10.106
Antigüedad: 16 años, 3 meses
Puntos: 2237
Respuesta: armar consulta dinámica con múltiples parametros

No veo la dependencia entre $cad1 y $cad2, lo único que te está complicando la consulta es que siempre incluyes and y en el for tienes que eliminar el agregado en la última iteración.

Código PHP:
Ver original
  1. <?php
  2. //recibo variables
  3. $fecha = $_GET['fecha'];
  4. $anio = $_GET['anio'];
  5. $trim = $_GET['trim'];
  6. $clases = $_GET['clases']; //arreglo
  7.  
  8. $query = "select * from tabla where "; //esta linea siempre sera igual
  9. $filtros = array("id='$id'"); // Inicializas filtros con ID
  10.  
  11. // Utiliza if's anidados, el código queda más legible
  12. if($fecha!="s"){
  13.    //si el input de fecha no esta vació
  14.    $filtros[] = "fecha='$fecha' ";
  15. } else if($anio!="s" && $trim!="s"){
  16.     //si el usuario elige año y trimestre
  17.          //entonces yo armo la fecha de inicio y la fecha final en base al trimestre correspondiente
  18.          $trim = explode("/",$trim); //recibo el trimestre: mm-dd/mm-dd
  19.          $trim_ini = $trim[0];
  20.          $trim_fin = $trim[1];
  21.          $fecha_ini = $anio."-".$trim_ini;
  22.          $fecha_fin = $anio."-".$trim_fin;
  23.          //hago la condición de la consulta
  24.          $filtros[] = "fecha between '$fecha_ini' and '$fecha_fin' ";
  25. } else if($anio!="s"){
  26.        //si solo eligio el año
  27.        $filtros[] = "left(fecha, 4)='$anio' ";
  28. }
  29.  
  30. // Segunda parte
  31. $clase = explode(",",$clases);
  32.  
  33. // Recorres $clase directamente, con foreach(), no necesitas contar los elementos
  34. // $i es el índice que usabas en el for, $valor corresponde a $clase[$i]
  35. foreach($clase as $i => $valor) {
  36.     if($clase[$i] != 's') {
  37.         $filtros[] = "id_{$array_clases[$i]} = '$valor'";
  38.     }
  39. }
  40.  
  41. // No necesitas comparar cad1 y cad2, sólo concatenas lo que haya en $filtros
  42. $query .= implode(' and ', $filtros);
  43.  
  44. //concluyo la consulta con un order by
  45. $query .= " order by id_arch ASC";

La lógica siguie siendo la misma, excepto por la complicación que tenías con $cad1 y $cad2
__________________
- León, Guanajuato
- GV-Foto
  #5 (permalink)  
Antiguo 01/11/2012, 15:41
Avatar de catpaw  
Fecha de Ingreso: mayo-2010
Ubicación: xalapa
Mensajes: 856
Antigüedad: 14 años, 6 meses
Puntos: 23
Respuesta: armar consulta dinámica con múltiples parametros

Hola triby, no,

la dependencia la quite cuando implemente las cadenas auxiliares $cad1 y $cad2

pero me quedo con tu solución del arreglo filtros, con tu ejemplo ya me queda claro como lo puedo manipular y es mas practico!!

muchas gracias!!

Etiquetas: armar, formulario, mysql, parametros, sql, tabla, variables, usuarios
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 16:30.