MySQL с 2 левыми соединениями на одной таблице - PullRequest
3 голосов
/ 23 мая 2009

Я пытаюсь выполнить этот запрос:

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

Это даст мне несколько статей (от nt_noticias), и идея состоит в том, чтобы получить одновременно файл Video и Audio из таблицы mm_files.

Что происходит, когда у меня есть статья со звуком и видео, MySQL вернет 4 строки:

  • со звуком (видео нулевое)
  • с видео (звук нулевой)
  • со всеми нулями
  • со звуком И видео

Как я могу "заставить" вернуть только одну строку на статью с любым существующим видео И аудио, связанным? Что я тут не так делаю?

Ответы [ 3 ]

1 голос
/ 23 мая 2009

Я думаю Вы хотите что-то вроде этого:

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

Я думал так:

Вы хотите максимум один аудиофайл и один видеофайл. На Noticia доступно несколько файлов, поэтому вам нужно убедиться, что в объединение попадает не более одного файла для каждого типа. Это также означает, что вам нужно дважды присоединиться к таблице ntNoticias_mmFiles & mdash; один раз для каждого типа.

Это то, что должны делать подзапросы в условиях соединения: выбрать одну строку для каждого типа файла. Идя оттуда, вы ЛЕВЫЕ ПРИСОЕДИНЯЕТЕСЬ к остальным данным, как вы уже это сделали.

1 голос
/ 23 мая 2009

JOIN вернет все комбинации, вот в чем проблема.
Если у вас есть только один аудио и / или видеофайл на статью, то вы можете посмотреть на подвыборы. В SQL Server это будет выглядеть примерно так (непроверенный код):

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

Обратите внимание, что на больших наборах данных это может работать плохо, так как подвыборы в этом примере выполняются отдельно для каждой строки, возвращаемой во внешний запрос. Например, если вы вернете 10000 статей, на сервере будет фактически выполнено 20 001 запрос. Есть другие возможные ответы, чтобы преодолеть это, но они становятся более сложными (я подозреваю, что вы могли бы что-то сделать с производной таблицей, но это ускользает от меня на данный момент).

0 голосов
/ 23 мая 2009

Возможно, вы хотите оптимизировать этот запрос на присоединение к представлению. Это большой запрос, и с таким количеством объединений он будет довольно неэффективным. Кроме того, представление помогает вам отлаживать объединения и в основном упрощает, позволяя вам писать свои объединения (в представлении) и предложение WHERE (в вашем выборе из представления) отдельно, что может помочь в отладке запросов.

...