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?

È stato utile?

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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top