2012-02-02 7 views
13

In MySQL:Selezionare righe da una tabella in cui riga in un'altra tabella con la stessa id ha un particolare valore in un'altra colonna

Se abbiamo due tabelle:

comments 
key | value 
================= 
1  | foo 
2  | bar 
3  | foobar 
4  | barfoo 

e:

meta 
comment_key | value 
========================= 
1    | 1 
2    | 1 
3    | 2 
4    | 1 

Desidero ottenere i commenti dalla tabella comment che hanno uno comment_key corrispondente nella tabella meta con uno specifico value (colonna value nella tabella meta).

Per esempio, mi piacerebbe per selezionare tutte le righe della tabella comment che hanno un value di 1 nella tabella meta:

mi aspetto questi risultati:

key | value 
================= 
1  | foo 
2  | bar 
4  | barfoo 

E se dovessi selezionare tutte le righe dalla tabella comment che hanno uno 2 nella tabella meta:

Mi aspetto questo risultato:

key | value 
================= 
3  | foobar 

Spero davvero che qualcuno possa aiutare, grazie a tutti in anticipo!

Penso di aver bisogno di unirsi? Qualsiasi suggerimento sarebbe fantastico e, se possibile, una breve spiegazione in modo da poter capire dove stavo sbagliando -> così saprò per la prossima volta!

risposta

20

Io in realtà non lo consigliano un JOIN per questo — o meglio, mi consiglia un "semijoin", che è un concetto relazionale-algebra non direttamente espressi in SQL. Un semijoin è essenzialmente un join in cui si desidera recuperare i record da una sola tabella, ma a condizione che abbiano record corrispondenti in una tabella diversa.

In notazione SQL, questo concetto è espresso indirettamente in base an IN clause, con un subquery:

SELECT key, value 
    FROM comments 
WHERE key IN 
     (SELECT comment_key 
      FROM meta 
      WHERE value = 1 
     ) 
; 

(MySQL effettivamente finire traduzione che di nuovo in un semijoin internamente — essenzialmente una sorta di degenerato inner- unisciti a — ma la clausola IN è il modo naturale di esprimerla in SQL raw.)

+1

correzione - non importa se vengono utilizzati i predicati 'join',' exists' o 'in', sono tutti semi join - definiti come join che restituiscono righe da una tabella in base all'esistenza di righe correlate in un'altra tabella. –

+2

@ JCooper: non lo vedo in questo modo. Supponiamo che per ogni record in 'parent', ci siano zero, uno o più record in' child'. Quindi un semi-join includerebbe zero o una copia di ogni record 'parent', mentre un SQL' INNER JOIN' includerebbe più copie di alcuni record 'parent'. Ma posso vederlo a modo tuo. Nell'algebra relazionale, un semi-join è equivalente a un inner-join seguito da una proiezione appropriata; quindi possiamo fare in modo che questa diventi una differenza tra le proiezioni SQL 'SELECT' e relazionale-algebra piuttosto che tra SQL' INNER JOIN' e semi-joins relazionale-algebra. – ruakh

+1

Wow, ero così vicino, ho avuto '=' invece di 'IN'! Grazie, funziona a meraviglia! –

0

Stai cercando un semplice equi-join di vaniglia qui.

SELECT `comment`.`key` AS `key`, 
     `comment`.`value` AS `value` 
    FROM `comments` 
     JOIN `meta` 
      ON `comments`.`key` = `meta`.`comment_key` 
    WHERE `meta`.`value` = 1; 

io non sono davvero sicuro che tipo di consigli che stai cercando qui, ma si può leggere di più sull'argomento (non MySQL specifico) a Wikipedia's SQL JOIN page.

io consiglierei di indicizzazione sui comment. key e meta. comment_key con entrambi gli indici PRIMARY KEY assumendo che ci sia solo 1 riga meta per riga comment (le CHIAVI PRIMARIE sono UNICHE per definizione).Se si desidera consentire più di 1 meta per comment, aggiungere una colonna separata dell'indice id a meta e rendere PRIMARY KEY con comment_key solo un indice b-tree.

Non sono nemmeno sicuro di come la prestazione di questo sarà paragonata alla risposta "semi-join" anche elencata, ma, per me, questo è il modo più semplice e naturale per esprimere la query; con solo due tabelle, tuttavia, non dovrebbe essere troppo difficile da ottimizzare per MySQL.

+0

Non sono sicuro che menzionare gli indici non superi la domanda in modo inappropriato o meno. Ho appena visto troppi programmatori che non riescono a prenderli in considerazione poiché le query sono sempre veloci sui dati di test con una dozzina di righe per tabella o meno. – SnowCrash

+0

Questo non produrrebbe righe duplicate nel genitore se ci sono più file secondarie? – CMCDragonkai

0

userei "INNER JOIN" nel seguente modo:

SELECT comments.key, comments.value FROM comments 
INNER JOIN meta ON comments.key=meta.comment_key WHERE meta.value = 1; 

Cheers! ;-)

Problemi correlati