【问题标题】:MySQL with 2 LEFT JOINs on the same tableMySQL 在同一张表上有 2 个 LEFT JOIN
【发布时间】:2009-05-23 16:28:38
【问题描述】:

我正在尝试运行此查询:

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),我的想法是同时从mm_files 表中获取VideoAudio 文件。

发生的情况是,当我有一篇有声音和视频的文章时,MySQL 会返回 4 行:

  • 有声音(视频为空)
  • 有视频(声音为空)
  • 全部为空
  • 有声音和视频

如何“强制”它在每篇文章中只返回一行并关联任何现有的视频和音频?我在这里做错了什么?

【问题讨论】:

    标签: sql mysql left-join


    【解决方案1】:

    认为你想要这样的东西:

    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 表两次——每种类型一次。

    这就是连接条件中的子查询应该做的事情:每种文件类型选择一行。从那里继续,您可以将其余数据加入其中,就像您已经做的那样。

    【讨论】:

    • LIMIT 子句在查询中不起作用,因为我在 MySQL 5.0 上,但我用 GROUP BY noticia_id 替换它并且工作得很好。谢谢一堆!
    • 我总是忘记 MySQL 不处理子查询中的 LIMIT。 :-) 但我很高兴能帮上忙。
    【解决方案2】:

    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
    

    请注意,在大型数据集上,这可能会表现不佳,因为此示例中的子选择是针对返回到外部查询的每一行单独执行的。例如,如果您返回 10,000 篇文章,那么实际上将在服务器上执行总共 20,001 个查询。 还有其他可能的答案来克服这个问题,但他们会更多地参与(我怀疑你可以用派生表做一些事情,但目前我还没有想到)。

    【讨论】:

      【解决方案3】:

      您可能希望将该连接查询优化为视图。这是一个很大的查询,而且有这么多的连接,效率会很低。此外,视图可以帮助您调试连接,并且通过允许您分别编写连接(在视图中)和 WHERE 子句(在视图中的选择中)来帮助调试查询,从而基本上简化了操作。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-05-19
        • 2021-01-25
        • 2015-09-02
        • 1970-01-01
        • 2011-10-18
        • 2012-03-15
        • 2012-01-02
        相关资源
        最近更新 更多