SQL - TERM de autocomplete en SQL

 
Vista:
sin imagen de perfil

TERM de autocomplete en SQL

Publicado por cotarejo (12 intervenciones) el 15/07/2015 19:09:51
Buenas tardes, estoy usando una consulta que debería de devolverme todos los registros que contengan cierta letra... por ejemplo la e, y al hacer la consulta me devuelve todos los registros independientemente de que tengan la e o no... la consulta es para hacer un autocomplete de jquery y hace tal que esto:


SELECT tablaplatos.primerprimero, tablaplatos.segundoprimero, tablaplatos.tercerprimero, tablaplatos.primersegundo, tablaplatos.segundosegundo, tablaplatos.tercersegundo, tablaplatos.primerpostre, tablaplatos.segundopostre, tablaplatos.tercerpostre FROM tablaplatos WHERE primerprimero like :term OR segundoprimero like :term OR tercerprimero like :term OR primersegundo like :term OR segundosegundo like :term OR tercersegundo like :term OR primerpostre like :term OR segundopostre like :term OR tercerpostre like :term")

yo le digo que es la e y me devulve esto:

["lentejas","carne estofada","alubias pintas","filete ternera","merluza al horno","sardinas","platano","flan","yogurt","espaguetis","arroz con bogavante","paella","brochetas","sardinas","huevos con pimientos","queso fresco","melon","sandia"]

y por ejemplo la sandía o las alubias pintas no tienen e pero aún así me sigue devolviendo eso la consulta en SQL


¿qué hago mal?? sé que está mal hecha la consulta pero no veo porqué... ggrrrrr


Gracias.
Valora esta pregunta
Me gusta: Está pregunta es útil y esta claraNo me gusta: Está pregunta no esta clara o no es útil
0
Responder
sin imagen de perfil
Val: 806
Bronce
Ha mantenido su posición en SQL (en relación al último mes)
Gráfica de SQL

TERM de autocomplete en SQL

Publicado por leonardo_josue (1173 intervenciones) el 16/07/2015 16:10:41
Hola cotarejo:

¿Cómo estás armando o qué contiene el parámetro :term? lo más seguro es que el problema esté ahí, pero al no colocar exactamente la consulta que estás ejecutando, no te podemos dar una respuesta puntual. Tampoco nos dices con qué BD's estás trabajando, pero puedo suponer que todo el problema está en los operadores "comodín" que utilizas en el like. Veamos este ejemplo. Supongamos que tienes esta tabla:

1
2
3
4
5
6
7
8
9
10
11
12
13
mysql> SELECT * FROM tabla1;
+------+---------------+
| id_1 | descripcion   |
+------+---------------+
|    1 | uno           |
|    2 | dos           |
|    3 | tres          |
|    4 | otro uno      |
|    5 | con uno y dos |
|    6 | uno al inicio |
|    7 | universo      |
+------+---------------+
7 rows in set (0.00 sec)

El uso más común del LIKE es para encontrar cadenas que CONTENGAN una subcadena... en cualquier lugar, supongamos que queremos buscar la palabra uno, entonces hacemos algo como esto:

1
2
3
4
5
6
7
8
9
10
mysql> SELECT * FROM tabla1 WHERE descripcion LIKE '%uno%';
+------+---------------+
| id_1 | descripcion   |
+------+---------------+
|    1 | uno           |
|    4 | otro uno      |
|    5 | con uno y dos |
|    6 | uno al inicio |
+------+---------------+
4 rows in set (0.00 sec)

Esta condición nos encuentra la palabra en cualquier parte (al inicio, en medio o al final de la cadena).

Si quieres encontrar sólo las cadenas que INICIAN con la palabra uno, entonces tienes que cambiar el patrón en el LIKE:

1
2
3
4
5
6
7
8
mysql> SELECT * FROM tabla1 WHERE descripcion LIKE 'uno%';
+------+---------------+
| id_1 | descripcion   |
+------+---------------+
|    1 | uno           |
|    6 | uno al inicio |
+------+---------------+
2 rows in set (0.00 sec)

De manera semejante, si quieres encontrar las cadenas que TERMINAN con uno, cambias el patrón:

1
2
3
4
5
6
7
8
mysql> SELECT * FROM tabla1 WHERE descripcion LIKE '%uno';
+------+-------------+
| id_1 | descripcion |
+------+-------------+
|    1 | uno         |
|    4 | otro uno    |
+------+-------------+
2 rows in set (0.00 sec)

Entonces, el comportamiento que estás teniendo me hace suponer que estás armando mal el patrón de búsqueda.

Ahora bien, tienes OTRO PROBLEMA MUY GRAVE... y es con el uso de los OR's... checa este otro ejemplo:

1
2
3
4
5
6
7
8
9
10
11
mysql> SELECT * FROM tabla2;
+------+-------------+--------------+
| id_1 | descripcion | descripcion2 |
+------+-------------+--------------+
|    1 | uno         | one          |
|    2 | dos         | two          |
|    3 | tres        | three        |
|    4 | cuatro      | four         |
|    5 | cinco       | five         |
+------+-------------+--------------+
5 rows in set (0.00 sec)

Si quieres buscar las descripciones que CONTENGAN la letra e entonces haces algo como esto:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
mysql> SELECT descripcion FROM tabla2 WHERE descripcion LIKE '%e%';
+-------------+
| descripcion |
+-------------+
| tres        |
+-------------+
1 row in set (0.00 sec)
 
mysql> SELECT descripcion2 FROM tabla2 WHERE descripcion2 LIKE '%e%';
+--------------+
| descripcion2 |
+--------------+
| one          |
| three        |
| five         |
+--------------+
3 rows in set (0.00 sec)

¿Pero qué pasa cuando colocas las condiciones OR?

1
2
3
4
5
6
7
8
9
10
11
12
mysql> SELECT descripcion, descripcion2
    -> FROM tabla2
    -> WHERE
    -> descripcion LIKE '%e%' OR descripcion2 LIKE '%e%';
+-------------+--------------+
| descripcion | descripcion2 |
+-------------+--------------+
| uno         | one          |
| tres        | three        |
| cinco       | five         |
+-------------+--------------+
3 rows in set (0.00 sec)

Ni la palabra UNO ni la palabra CINCO contienen la letra e, entonces tu lógica sería que no deberían aparecer, pero el problema es que cuando haces condiciones OR con que una de las condiciones se cumpla, se hace verdadera. en este caso, ONE y FIVE si tienen contienen la letra e. Si quisieras OBLIGAR a que ambos campos tengan la letra e, entonces DEBES UTILIZAR UN OPERADOR AND:

1
2
3
4
5
6
7
8
9
10
mysql> SELECT descripcion, descripcion2
    -> FROM tabla2
    -> WHERE
    -> descripcion LIKE '%e%' AND descripcion2 LIKE '%e%';
+-------------+--------------+
| descripcion | descripcion2 |
+-------------+--------------+
| tres        | three        |
+-------------+--------------+
1 row in set (0.00 sec)

Ahora bien, te tengo que comentar que lo que estás tratando de hacer ES TERRIBLE EN DESEMPEÑO... de entrada el operador LIKE es uno de los que peor performance tiene, y además al hacer tantos OR's y tantos LIKE's te puedo asegurar que tu consulta será muy lenta.

Lo recomendable es NO UTILIZAR CONDICIONES LIKE EN TUS CONSULTAS. Una alternativa son las BÚSQUEDAS DE TEXTO COMPLETO, aunque estas no son soportadas por todos los DBMS's. Pregúntale a SAN GOOGLE acerca de este tipo de búsquedas y si la BD's con la que estás trabajando las soporta, haz algunas pruebas, te aseguro que tendrás mejores resultados.

Saludos
Leo.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
sin imagen de perfil

TERM de autocomplete en SQL

Publicado por cotarejo (12 intervenciones) el 16/07/2015 17:49:00
Gracias por contestar, pero no quiero que se cumplan dos condiciones con AND, quiero que se cumpla una de ellas.. la consulta es esta:

function autocompletarplato($pdo){
$sentencia = $pdo->prepare("SELECT tablaplatos.primerprimero, tablaplatos.segundoprimero, tablaplatos.tercerprimero, tablaplatos.primersegundo, tablaplatos.segundosegundo, tablaplatos.tercersegundo, tablaplatos.primerpostre, tablaplatos.segundopostre, tablaplatos.tercerpostre FROM tablaplatos WHERE primerprimero like :term AND segundoprimero like :term AND tercerprimero like :term AND primersegundo like :term AND segundosegundo like :term AND tercersegundo like :term AND primerpostre like :term AND segundopostre like :term AND tercerpostre like :term");
$sentencia->execute(array('term' => '%'.$_GET['term'].'%'));
return $sentencia;
}

que esta función es llamada desde:

include 'conexiones.php';

if (isset($_GET['term'])){
$return_arr = array();
try {
$stmt = autocompletarplato($pdo);
while($row = $stmt->fetch()) {
$return_arr[] = $row['primerprimero'];
$return_arr[] = $row['segundoprimero'];
$return_arr[] = $row['tercerprimero'];
$return_arr[] = $row['primersegundo'];
$return_arr[] = $row['segundosegundo'];
$return_arr[] = $row['tercersegundo'];
$return_arr[] = $row['primerpostre'];
$return_arr[] = $row['segundopostre'];
$return_arr[] = $row['tercerpostre'];
}
} catch(PDOException $e) {
echo 'ERROR: ' . $e->getMessage();
}
echo json_encode($return_arr);
}


la cual viene desde un autocomplete de jquery:

$(function() {
$("#plato").autocomplete({
source: "php/autocompletarplato.php",
minLength: 1
});
});
</script>


y cuando pongo la letra por ejemplo "e" me devuelve todos los resultados independientemente de si tienen E o no.

la tabla es esta:

tablaplatos


Sigo sin saber porqué y me estoy volviendo loco!!!

Gracias.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
sin imagen de perfil
Val: 806
Bronce
Ha mantenido su posición en SQL (en relación al último mes)
Gráfica de SQL

TERM de autocomplete en SQL

Publicado por leonardo_josue (1173 intervenciones) el 16/07/2015 18:40:29
Hola de nuevo:

Antes de que te vuelvas loco RESPIRA, CUENTA HASTA DIEZ y LEE CUIDADOSAMENTE TODOS LO QUE TE PUSE EN EL POST PASADO

1
no quiero que se cumplan dos condiciones con AND, quiero que se cumpla una de ellas

Insisto en que si se cumple una de ellas entonces NO IMPORTA QUE EL RESTO DE LOS CAMPOS NO TENGAN LA LETRA e... si uno de los campos que está en el WHERE tiene una e, entonces ES PERFECTA Y ABSOLUTAMENTE CORRECTO QUE SE MUESTRE EL REGISTRO:

Vuelvo a poner este ejemplo:

1
2
3
4
5
6
7
8
9
10
11
12
mysql> SELECT descripcion, descripcion2
    -> FROM tabla2
    -> WHERE
    -> descripcion LIKE '%e%' OR descripcion2 LIKE '%e%';
+-------------+--------------+
| descripcion | descripcion2 |
+-------------+--------------+
| uno         | one          |
| tres        | three        |
| cinco       | five         |
+-------------+--------------+
3 rows in set (0.00 sec)

Las búsquedas se hacen a nivel DE REGISTRO... en el primero de los casos la palabra ONE contiene la letra e, por lo tanto TODO EL REGISTRO SE MUESTRA, haciendo que aparezca el campo con UNO, no importa que esta palabra NO CONTENGA LA LETRA E...

Esto ESTA CORRECTO no hay error, así es la lógica, así debe de funcionar la consulta y así es como funciona... La pregunta sería ¿tú que esperas como resultado?

Creo que estás contando manzanas y quieres obtener como resultado naranjas... es decir, estás equivocando completamente el camino. A partir de los registros que dices que tienes en tu tabla, dinos qué es lo que esperas obtener como resultado y te podremos dar alguna otra alternativa.

Saludos
Leo,
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
sin imagen de perfil

TERM de autocomplete en SQL

Publicado por cotarejo (12 intervenciones) el 16/07/2015 22:49:59
Si pues si es como tú dices entonces está mostrando justo lo que le estoy preguntando, por lo que deduzco que estoy haciendo mal la pregunta.... yo lo que quiero es que en un campo de html input tecleo una letra, vamos a poner por ejemplo la letra "e" y que me salgan todas las comidas que contentan esa letra "e" es decir %e% ya que me da igual si está al principio al final o en medio, sólo las comidas que contentan letra e, como puede ser lEntEjas, pero que no me salga sandía. Muestro una captura de pantalla de lo que me muestra el autocomplete() y tacho en rojo lo que no quiero que aparezca:


autocomplete


Sé que el problema está en la consulta SQL que hago, y por lo que me dices sé que está mal hecha, pero no sabría cómo hacerla.


Gracias.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
sin imagen de perfil
Val: 806
Bronce
Ha mantenido su posición en SQL (en relación al último mes)
Gráfica de SQL

TERM de autocomplete en SQL

Publicado por leonardo_josue (1173 intervenciones) el 16/07/2015 23:18:24
Hola de nuevo:

Pues lo dicho, estabas contando manzanas queriendo obtener naranjas :P. Con la manera que tienes tus datos, NO PUEDES TRATAR LAS BÚSQUEDAS A NIVEL DE REGISTRO, sino que tienes que hacerlo sólo a nivel de COLUMNAS... puedes utilizar UNION's, para obtener un sólo resultado. Continuo con el ejemplo que puse, partiendo de esta tabla:

1
2
3
4
5
6
7
8
9
10
11
mysql> SELECT * from tabla2;
+------+-------------+--------------+
| id_1 | descripcion | descripcion2 |
+------+-------------+--------------+
|    1 | uno         | one          |
|    2 | dos         | two          |
|    3 | tres        | three        |
|    4 | cuatro      | four         |
|    5 | cinco       | five         |
+------+-------------+--------------+
5 rows in set (0.00 sec)

Lo que haces es poner dos subconsultas con un UNION, donde cada subconsulta hace referencia a uno de los campos...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
mysql> SELECT descripcion
    ->   FROM tabla2
    ->   WHERE descripcion LIKE '%e%'
    -> UNION
    -> SELECT descripcion2 descripcion
    ->   FROM tabla2
    ->   WHERE descripcion2 LIKE '%e%';
+-------------+
| descripcion |
+-------------+
| tres        |
| one         |
| three       |
| five        |
+-------------+
4 rows in set (0.00 sec)

Ahora si, NO TIENES EL PROBLEMA DEL OR O EL AND porque las búsquedas las limitas a columnas NO A REGISTROS (que es lo que he insistido en mis dos mensajes anteriores), esto tendrías que hacerlo por cada uno de los campos que tienes en tu tabla Te quedará una consulta enorme, pero de acuerdo a como tienes tus datos, es la única forma de hacerlo... Puedes plantearte también cambiar de modelo de datos, puedes tener la misma información en forma de columnas, es decir, en lugar de tener esto:

1
2
3
4
5
6
+----+----------+--------------+---------------------+
| id | nombre   | primeprimero | segundo             |
+----+----------+--------------+---------------------+
|  1 | labrador | lentejas     | carne estofada      |
|  2 | bombi    | espaguetis   | arroz con bogavante |
+----+----------+--------------+---------------------+

tener un modelo asi:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
tabla_uno
+----+----------+
| id | nombre   |
+----+----------+
|  1 | labrador |
|  2 | bombi    |
+----+----------+
 
tabla_dos
+--------+----------+--------------+---------------------+
| id_dos | id_uno   | tipo         | descripcion         |
+--------+----------+--------------+---------------------+
|  1     | 1        | primeprimero | lentejas            |
|  2     | 1        | primesegundo | carne estofada      |
|  3     | 1        | tercerprimero| alubias pintas      |
...
...
|  20    | 2        | primeprimero | espaguetis          |
|  21    | 2        | primesegundo | arroz con bogavante |
...
...
+--------+----------+--------------+---------------------+

Esto haría más simple la consulta que quieres hacer.

Saludos
Leo
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
2
Comentar
sin imagen de perfil

TERM de autocomplete en SQL

Publicado por cotarejo (12 intervenciones) el 17/07/2015 23:02:47
OKKKKKKKKKKKKKKK por fin funciona!!!! con UNION ha funcionado correctamente!!!


Muchas gracias!!!!!!!!!!!!!!!


Ahora sólo me queda saber porqué en localhost funciona bien la creación de ficheros XML pero cuando lo subo al servidor web de internet me da un error de Error de lectura XML: mal formado

Ya lo he posteado en el foro de XML


Muchas gracias LEO!!!! ;)
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar