2012-06-15 16 views
8

Ho due tabelle nel mio database MySQL, uno è una biblioteca di tutti i libri presenti nel database, e l'altro è che contiene le singole righe corrispondenti a cui libri sono nella libreria di un utente.MySQL sinistra outer join, escludere gli elementi a seconda tavola appartenenti a utenti

Ad esempio:

Table Library

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

Collection Tavolo

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

Quello che voglio fare è eseguire una query che mostrerà tutti i libri che sono non nella raccolta di un utente. Posso eseguire la query per mostrare tutti i libri non in collezione qualsiasi dell'utente:

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

Questo funziona bene per quanto posso dire. L'esecuzione di questo in PHPMyAdmin comporterà la pubblicazione di tutti i libri non presenti nella tabella di raccolta.

Tuttavia, come faccio a limitare che a un certo utente? Ad esempio, con i dati fittizi di cui sopra, voglio libro 1 al risultato se l'utente 2 esegue la query, e nessun libro se l'utente 1 esegue la query.

La semplice aggiunta di uno AND user=[id] non funziona e con la mia conoscenza estremamente limitata delle dichiarazioni JOIN non riesco a ottenere alcun risultato.

Inoltre, l'ID dei risultati restituiti (della query mostrata, che non fa ciò che voglio ma funziona) è 0-- come faccio a verificare che l'ID restituito sia quello di library.id?

+0

si prega di mostrare la struttura della tabella reale e darci l'errore (se presente) che stai incontrando. La tua query menziona un campo chiamato "articolo" che non è nelle descrizioni della tabella. – bpeterson76

+0

Oops-- L'ho lasciato come articolo quando ho copiato e incollato. Dovrebbe essere "libro". Ho cambiato la domanda. –

risposta

12

Dovrete limitare la selezione LEFT JOIN solo ai libri che un particolare utente ha, quindi tutto ciò che è NULL nella tabella unita saranno righe (libri) per cui l'utente non ha nel suo/sua collezione:

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 

un'alternativa è:

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

Tuttavia, la prima soluzione è più ottimale come MySQL eseguirà il NOT IN subquery volta per ogni ro w piuttosto che una sola volta per l'intera query. Intuitivamente, ti aspetteresti che MySQL esegua la subquery una volta sola e la usi come una lista, ma MySQL non è abbastanza intelligente da distinguere tra sottoquery correlate e non correlate.

Come dichiarato here: "Il problema è che, per una dichiarazione che utilizza un subquery IN, l'ottimizzatore riscrive come un subquery correlata"

+0

Grazie! Ha funzionato perfettamente. Questa roba di "JOIN", per qualsiasi motivo, è difficile per me per avvolgere la mia mente ... –

+2

Il tuo ultimo paragrafo punta a un link in cui sono citate le subquery 'IN' e non le sottoquotazioni' NOT IN'. Quindi, quello che intendi, che le query con 'NOT IN' non sono ottimizzate bene sono sbagliate. Vedi questo ottimo post del blog: [NON IN vs NON ESISTE vs SINISTRA UNISCONO/È NULL: MySQL] (http://explainextended.com/2009/09/18/not-in-vs-not-exists-vs- left-join-is-null-mysql /) –

+0

Credo che non importa se è 'NOT IN' o' IN'. Il 'NOT' semplicemente inversa il valore booleano restituito da' IN'. Articolo interessante anche se +1 –

3

Che ne dici di questo? È semplicemente fuori di testa: non ho accesso a un database per testare adesso.(spiacente)

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

Ah ... Vedo Andrew M picchiarmi: O) –

+0

Grazie comunque per il tuo aiuto: P +1 –

+1

Grazie per il +1. Ho davvero bisogno di quelli, essendo completamente nuovo qui: O) –