2009-10-18 28 views
7

que actualmente tienen la siguiente fila en mi mesa:MySQL instrucción Select, cláusula WHERE 'IN'

  course_data: 
      user_id  days  <-- This is a varchar column. 
       405   1,3,5 

y yo estoy tratando de poner en práctica la siguiente instrucción SELECT:

SELECT usrID, usrFirst, usrLast, usrEmail 
    FROM tblUsers 
    WHERE usrID NOT IN 
    (
     SELECT users.usrID 
      FROM 
       `course_data` courses, 
       `tblUsers` users 
      WHERE 
       days IN ('$day') 
    ) 
    GROUP BY usrID 
    ORDER BY usrID 

Básicamente, quiere que esa fila (con el usuario 405) se omita si la variable $ day incluye un '1, 3 o 5'.

Por ejemplo, si $day = "1", debe devolver una consulta vacía (porque el número "1" está en la columna "1,3,5").

Sin embargo, no he encontrado que este sea el caso. Aunque $day = "1", aún devuelve esa fila.

La única forma en que no devolverá la fila es si $day= "1,3,5." Sin embargo, pensé que la cláusula IN() tomaría cualquier parte de mi variable y la aplicaría a esa columna.

¿Alguna idea de lo que estoy haciendo mal aquí? Gracias.

Respuesta

11

Debe utilizar the like keyword hacer una coincidencia parcial del campo Char:

where days like '%1%' 

Editar: VolkerK y Lukáš Lalinský tanto sugiera find_in_set de MySQL, que es probablemente mejor que like para lo que quiere hacer. Sin embargo, la siguiente recomendación sobre la normalización de su base de datos sigue siendo válida.

Sin embargo, no debe almacenar valores múltiples en un solo campo de base de datos. En su lugar, considerar el uso de dos tablas:

course_data: 
    user_id 

course_days: 
    user_id 
    day_number 

Entonces, tendría los siguientes datos:

course_data: 
    user_id 
    405 

course_days 
    user_id day_number 
    405  1 
    405  3 
    405  5 

Luego, puede consultar correctamente este esquema. Por ejemplo:

select cd.user_id 
from course_data as cd 
where cd.user_id not in 
    (
     select course_days.user_id 
     from course_days 
     where course_days.user_id = cd.user_id 
      and course_days.day_number = 1 
    ) 

(o, que debe estar cerca, no estoy exactamente seguro de lo que estamos tratando de lograr o lo que el resto de su esquema se parece, por lo que esta es una mejor estimación) .

+0

Gracias. Tienes razón sobre cambiar la estructura. Seguí adelante y lo hice. Gracias. – Dodinas

+0

"así que esta es una mejor suposición": otra idea (con suerte factible) es utilizar una subconsulta NOT EXISTS como se describe en http://dev.mysql.com/doc/refman/5.1/en/exists-and-not- Existe-subqueries.html en lugar de 'x NOT IN (subconsulta)' – VolkerK

+0

% como% daría 11 para una búsqueda de 1, por lo que realmente no se adapta, por lo que esta respuesta no se aplica realmente a la pregunta original. La respuesta de theomega parece más aplicable al OP. – Tarquin

14

Eliminar las comillas en la declaración IN. La sintaxis es:

... WHERE column IN (1,2,3) 

y no como usted lo utilizó

... WHERE column IN ('1,2,3') 

también ver la documentation en EN, hay más ejemplos.

+0

En realidad, lo siento, necesito algunas aclaraciones. Estoy haciendo algo mal aquí. Si uso: DONDE días EN (1), lo elimina correctamente y devuelve un resultado vacío. Pero si uso: DONDE días EN (3), no devuelve una consulta vacía. ¿Pensaría que debería eliminar la consulta porque '3' está en la consulta? ¿Algunas ideas? – Dodinas

+0

Supongo que es porque convierte "1,3,5" en una int (deteniéndose en la coma), y luego ve que coincide. – Yuliy

+0

No estoy seguro de por qué esta no es la respuesta aceptada para el escenario presentado en la publicación original, aunque acepto que la respuesta aceptada proporciona consejos para corregir malos hábitos de codificación. – Tarquin

0

días no tiene una lista de cadenas. Tiene una sola cuerda. ¿Está la cadena "1,3,5" dentro de una de las cadenas en {'1'}? Claramente la respuesta es no. Tanto en los días Refactor en una tabla diferente, o estar preparados para hacer una manipulación más cuerdas

2

Si entiendo su pregunta correctamente, quiere que el contenido del campo varchar sea tratado como una lista separada por comas y compruebe si esta lista no contiene un cierto valor. Para eso necesita la función find_in_set(str, strlist).
Pero tenga en cuenta que MySQL no puede usar un índice en ese caso y su consulta siempre necesitará una exploración de tabla completa. Es podría ser mejor no almacenar datos estructurados (y ejecutar comparaciones en los elementos individuales) en una sola columna, sino utilizar otra tabla y un JOIN como se ha sugerido en otras respuestas.

5

creo que la consulta que desea es:

SELECT usrID, usrFirst, usrLast, usrEmail 
FROM tblUsers 
WHERE usrID NOT IN (
    SELECT user_id 
    FROM course_data 
    WHERE find_in_set(?, days) > 0 
) 
ORDER BY usrID 

Pero usted debería considerar seriamente la normalización de la base de datos, de modo que cada día tiene su propia fila.

Cuestiones relacionadas