2012-06-15 10 views
8

Tengo dos tablas en mi base de datos MySQL, una es una biblioteca de todos los libros de la base de datos y la otra contiene filas individuales correspondientes a los libros en la biblioteca de un usuarioMySQL Left Outer Join, Excluye elementos en la segunda tabla perteneciente al usuario

Por ejemplo:

Tabla Biblioteca

`id`  `title`... 
=====  =========== 
    1   Moby Dick 
    2   Harry Potter 

Tabla Colección

`id`  `user`  `book` 
=====  ======  ======= 
    1   1   2 
    2   2   2 
    3   1   1 

Lo que quiero hacer es ejecutar una consulta que mostrará todos los libros que están no en la colección de un usuario. Puedo ejecutar esta consulta para mostrar todos los libros no en la colección de cualquier usuario:

SELECT * 
FROM `library` 
LEFT OUTER JOIN `collection` ON `library`.`id` = `collection`.`book` 
WHERE `collection`.`book` IS NULL 

Esto funciona muy bien en lo que puedo decir. Ejecutar esto en PHPMyAdmin dará como resultado todos los libros que no están en la tabla de recopilación.

Sin embargo, ¿cómo puedo restringir eso a un determinado usuario? Por ejemplo, con los datos ficticios anteriores, deseo que aparezca el libro 1 si el usuario 2 ejecuta la consulta, y no hay libros si el usuario 1 ejecuta la consulta.

Simplemente agregando un AND user=[id] no funciona, y con mi conocimiento extremadamente limitado de las declaraciones JOIN realmente no llego a ningún lado.

Además, el ID de los resultados que se devuelven (de la consulta que se muestra, que no hace lo que quiero pero funciona) es 0-- ¿Cómo me aseguro de que la ID devuelta sea la de library.id?

+0

muestra la estructura real de la tabla y nos da el error (si corresponde) que estás encontrando. Su consulta menciona un campo llamado "artículo" que no está en las descripciones de su tabla. – bpeterson76

+0

Vaya, lo dejé como artículo cuando copié y pegué. Debe ser "libro". He cambiado la pregunta. –

Respuesta

12

Vas a tener que limitar su selección a LEFT JOIN sólo los libros que un usuario particular tiene, entonces lo que es NULL en la tabla empalmado se filas (libros) para los que el usuario no tenga en su/su colección:

SELECT 
    a.id, 
    a.title 
FROM 
    library a 
LEFT JOIN 
    (
     SELECT book 
     FROM collection 
     WHERE user = <userid> 
    ) b ON a.id = b.book 
WHERE 
    b.book IS NULL 

Una alternativa es:

SELECT 
    a.id, 
    a.title 
FROM 
    library a 
WHERE 
    a.id NOT IN 
    (
     SELECT book 
     FROM collection 
     WHERE user = <userid> 
    ) 

Sin embargo, la primera solución es más óptima como MySQL, se ejecutará la subconsulta NOT IN una vez por cada ro w en lugar de solo una vez para toda la consulta. Intuitivamente, esperaría que MySQL ejecutara la subconsulta una vez y la usara como una lista, pero MySQL no es lo suficientemente inteligente como para distinguir entre subconsultas correlacionadas y no correlacionadas.

como se ha dicho here:

"El problema es que, por una declaración que utiliza una subconsulta IN, el optimizador reescribe como una consulta correlacionada."

+0

¡Gracias! Eso funcionó perfectamente. Este material de 'UNIRSE', por la razón que sea, me resulta difícil de entender ... –

+2

Su último párrafo apunta a un enlace donde se mencionan las subconsultas 'IN' y no las subconsultas 'NOT IN'. Entonces, lo que implica que las consultas con 'NOT IN' no están bien optimizadas es incorrecto. Vea esta gran publicación en el blog: [NO EN CONTRA DE NO EXISTE VS LEFT JOIN/IS NULL: MySQL] (http://explainextended.com/2009/09/18/not-in-vs-not-exists-vs- left-join-is-null-mysql /) –

+0

Creo que no importa si es 'NOT IN' o' IN'. El 'NOT 'simplemente invierte el booleano devuelto de' IN'. Interesante artículo, aunque +1 –

3

¿Qué le parece esto? Está fuera de mi cabeza: no tengo acceso a una base de datos para probar en este momento.(lo siento)

SELECT 
    * 
FROM 
    library lib 
WHERE 
    lib.id NOT IN (
     SELECT 
     book 
     FROM 
     collection coll 
     WHERE 
     coll.user =[id] 
    ) 
; 
+0

Ah ... Veo que Andrew M me ganó: O) –

+0

Gracias de todos modos su ayuda: P +1 –

+1

Gracias por el +1. Realmente los necesito, siendo completamente nuevo aquí: O) –