【问题标题】:Joining 3 tables efficiently in MYSQL在 MYSQL 中有效地连接 3 个表
【发布时间】:2011-02-25 18:01:13
【问题描述】:

我有 3 个这样的表:

图片(约 10,000 行)

id | place_id | filename 
---|----------|----------
 1 |     4    |  abc.jpg
 2 |     3    |  def.jpg
 3 |     4    |  ghi.jpg
 4 |     7    |  jkl.jpg

标签(约 100 行)

id |   name   |
---|----------|
 1 |   tagA   |
 2 |   tagB   |
 3 |   tagC   |
 4 |   tagD   |

tagsToImages(~30,000 行)

id |  tag_id  | image_id
---|----------|----------
 1 |     1    |    4
 2 |     3    |    2
 3 |     2    |    4
 4 |     1    |    1

例如,最后一个表格显示了 id = 1 的标签与 id = 4 的图像链接。

我有两个问题,一个很简单(我认为!),一个更难。

简单问题

给定一个place_id,我如何列出所有在该place_id 中有图像的标签?一个例子是:

给定place_id = 7,返回tagA,tagB。

难题

我想要做的是选择具有特定 place_id 的所有图像,并将每个图像与标签列表相关联,如下所示:

选择所有 place_id = 4,同时加入标签信息。

 filename |    tags    
-----------------------
  abc.jpg | tagA       
  ghi.jpg | tagA, tagB 

在 PHP 中通过执行多个查询会更好吗,还是可以使用 MYSQL 来做到这一点?

【问题讨论】:

    标签: php mysql join


    【解决方案1】:
    1. SELECT i.place_id, t.name as tag_name
      FROM images i
      INNER JOIN tagsToImages tti ON (tti.image_id = i.id)
      INNER JOIN tags t ON (t.id = tti.tag_id)
      WHERE i.place_id = 7

    2. SELECT i.filename, GROUP_CONCAT(t.name SEPARATOR ',') AS tags
      FROM images i
      INNER JOIN tagsToImages tti ON (tti.image_id = i.id)
      INNER JOIN tags t ON (t.id = tti.tag_id)
      WHERE i.place_id = 4 GROUP BY i.filename

    如果可能,最好避免多次查询。
    *请注意GROUP_CONCAT 的最大长度由group_concat_max_len 变量控制。如果您希望获得一长串串联字符串,则可能需要更改默认值。

    更新
    如果您希望查询显示没有关联标签的图像,请将INNER JOINs 更改为LEFT JOINs

    【讨论】:

    • 非常感谢!你是某种巫师吗——这太神奇了。我的最佳尝试运行时间太长,以至于我放弃了 - 运行时间约为 300-400 毫秒...
    • 我刚回来问如何显示没有标签的图像,你已经回答了!非常感谢!
    • 我还有一个问题——如果我想用另一个表中的地点名称加入地点,为什么这个查询不起作用? SELECT i.id, i.filename, i.rating, i.caption, i.height, i.width, p.name, GROUP_CONCAT(t.name SEPARATOR ', ') AS tags FROM gallery i, gallery_places p LEFT JOIN gallery_tagsToimages tti ON (tti.image_id = i.id) LEFT JOIN gallery_tags t ON (t.id = tti.tag_id) 其中 i.place = 101 AND i.place = p.id GROUP BY i.filename ORDER BY i.rating DESC , i.modified DESC LIMIT 16(我已经重命名了一些表)
    • 我认为您的查询有效,但不是您想要的方式。您按 i.filename 分组,因此 mysql 只选择具有指定 i.filename 的任何 i.id, i.rating, i..., p.name。另外,我宁愿使用JOIN 而不是WHERE 来加入表格
    【解决方案2】:

    简单的问题

    SELECT name 
    FROM images 
    RIGHT JOIN tagsToImages on images.id = tagsToImages.image_id 
    RIGHT JOIN tags ON tags.tag_id = tagsToImages.image_id 
    WHERE place_id = '7'
    

    【讨论】:

      【解决方案3】:

      对于简单的问题,使用join会更高效:

      select
          t.name as `Tag`
      from
          images i
      left join
          tagsToImages ti on ti.image_id = i.id
      left join
          tags t on t.id = ti.tag_id
      where
          place_id = $place_id
      

      对于棘手的问题,请参阅GROUP_CONCAThttp://dev.mysql.com/doc/refman/5.0/en/group-by-functions.html#function_group-concat

      【讨论】:

        【解决方案4】:

        使用连接发出单个查询比在 PHP 中添加循环、多个数据结构和手动比较值要好。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2013-04-21
          • 2023-03-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-04-07
          • 2015-09-05
          相关资源
          最近更新 更多