MySQL con 2 LEFT JOIN nella stessa tabella
Domanda
Sto cercando di eseguire questa query:
SELECT
Destaque.destaque, Noticia.id, Noticia.antetitulo,
Noticia.titulo, Noticia.lead, Noticia.legenda,
Noticia.publicacao, Seccao.descricao, Album.pasta,
Foto.ficheiro, Foto.descricao, Cronista.nome,
Cronista.profissao, Cronista.ficheiro,
AudioFile.*, AudioCollection.*, VideoFile.*, VideoCollection.*
FROM
nt_highlights AS Destaque
LEFT JOIN nt_noticias AS Noticia ON Destaque.noticia_id = Noticia.id
LEFT JOIN mm_fotos AS Foto ON Noticia.foto_id = Foto.id
LEFT JOIN nt_temas AS Seccao ON Noticia.tema_id = Seccao.id
LEFT JOIN mm_albuns AS Album ON Foto.album_id = Album.id
LEFT JOIN nt_cronistas AS Cronista ON Cronista.id = Noticia.cronista_id
LEFT JOIN ntNoticias_mmFiles AS Rel ON Rel.noticia_id = Noticia.id
LEFT JOIN mm_files AS AudioFile ON AudioFile.id = Rel.file_id
LEFT JOIN mm_coleccoes AS AudioCollection ON AudioFile.coleccao_id = AudioCollection.id
LEFT JOIN mm_files AS VideoFile ON VideoFile.id = Rel.file_id
LEFT JOIN mm_coleccoes AS VideoCollection ON VideoFile.coleccao_id = VideoCollection.id
WHERE
Destaque.area_id = 1
AND Noticia.paraPublicacao = 1
AND Noticia.publicacao <= NOW()
AND (AudioFile.mimeType != '' OR AudioFile.id IS NULL)
AND (VideoFile.mimeType = '' OR VideoFile.id IS NULL)
ORDER BY
Destaque.destaque
Questo mi otterrà una serie di articoli (dal nt_noticias
) e l'idea è di ottenere al tempo stesso un Video
e un file Audio
dalla tabella mm_files
.
Quello che succede è che quando ho un articolo con un suono e un video, MySQL tornerà 4 file:
- con il suono (video è nullo)
- con il video (audio è nullo)
- con tutti i null
- con il suono e il video
Come posso "forzare" per restituire solo una riga per articolo con qualsiasi video e audio esistente associato? Che cosa sto facendo male qui?
Soluzione
I pensare si desidera qualcosa di simile a questo:
SELECT
Destaque.destaque, Noticia.id, Noticia.antetitulo,
Noticia.titulo, Noticia.lead, Noticia.legenda,
Noticia.publicacao, Seccao.descricao, Album.pasta,
Foto.ficheiro, Foto.descricao, Cronista.nome,
Cronista.profissao, Cronista.ficheiro,
AudioFile.*, AudioCollection.*, VideoFile.*, VideoCollection.*
FROM
nt_highlights AS Destaque
LEFT JOIN nt_noticias AS Noticia ON Destaque.noticia_id = Noticia.id
LEFT JOIN mm_fotos AS Foto ON Noticia.foto_id = Foto.id
LEFT JOIN nt_temas AS Seccao ON Noticia.tema_id = Seccao.id
LEFT JOIN mm_albuns AS Album ON Foto.album_id = Album.id
LEFT JOIN nt_cronistas AS Cronista ON Cronista.id = Noticia.cronista_id
LEFT JOIN ntNoticias_mmFiles AS AudioRel ON Rel.noticia_id = Noticia.id
AND AudioRel.file_id IN (
SELECT file_id
FROM ntNoticias_mmFiles
WHERE noticia_id = Noticia.id AND IsAudioFile = 1 /* whatever the check is */
LIMIT 1
)
LEFT JOIN mm_files AS AudioFile ON AudioFile.id = Rel.file_id
LEFT JOIN mm_coleccoes AS AudioCollection ON AudioFile.coleccao_id = AudioCollection.id
LEFT JOIN ntNoticias_mmFiles AS VideoRel ON VideoRel.noticia_id = Noticia.id
AND VideoRel.file_id IN (
SELECT file_id
FROM ntNoticias_mmFiles
WHERE noticia_id = Noticia.id AND IsVideoFile = 1 /* whatever the check is */
LIMIT 1
)
LEFT JOIN mm_files AS VideoFile ON VideoFile.id = Rel.file_id
AND VideoFile.IsVideoFile = 1
LEFT JOIN mm_coleccoes AS VideoCollection ON VideoFile.coleccao_id = VideoCollection.id
WHERE
Destaque.area_id = 1
AND Noticia.paraPublicacao = 1
AND Noticia.publicacao <= NOW()
ORDER BY
Destaque.destaque
Il mio pensiero era questo:
Si desidera un file audio e un file video, al massimo. Ci sono diversi file disponibili per Noticia
, quindi è necessario fare in modo che un massimo di un file per ogni tipo entra nel join. Questo significa anche avere a unirsi nella tabella ntNoticias_mmFiles
due volte -. Una volta al tipo
Questo è ciò che i sub-query nelle condizioni di join sono tenuti a fare: selezionare una riga per ogni tipo di file. Proseguendo da lì si LEFT JOIN il resto dei dati in, proprio come già fate.
Altri suggerimenti
Il ENTRA restituirà tutte le combinazioni, questo è il problema.
Se si dispone di un solo audio e / o file video per ogni articolo, allora si potrebbe desiderare di guardare subselect.
In SQL Server questo sarebbe simile (codice non testato):
SELECT title,
(select TOP 1 audio from audio where audio.aid = articles.id) as Audio,
(select TOP 1 video from video where video.aid = articles.id) as Video
FROM articles
Fare attenzione che in grandi serie di dati può eseguire male i subselect in questo esempio vengono eseguite singolarmente per ogni riga restituita al query esterna. Ad esempio, se si torna 10.000 articoli poi un totale di 20.001 domande sarebbe in realtà essere eseguito sul server. Ci sono altre risposte possibili per superare questo ma ottengono più coinvolti (ho il sospetto che si possa fare qualcosa con una tabella derivata, ma mi sfugge al momento).
Probabilmente si desidera ottimizzare che uniscono query in una vista. Si tratta di una query di grandi dimensioni, e con che molti unisce, che sta per essere piuttosto inefficiente. In più, una vista aiuta il debug le giunture e sarà essenzialmente semplifica consentendo di scrivere il vostro unisce (nella vista) e la clausola WHERE (nel selezionare dal punto di vista) a parte, che può aiutare con il debug delle query.