【问题标题】:Need some help with a MySQL subquery count需要一些有关 MySQL 子查询计数的帮助
【发布时间】:2010-03-19 09:49:03
【问题描述】:

我遇到了自己的 MySQL 查询技能限制,所以我希望一些 SQL 专家可以帮助解决这个问题。情况如下:

我有可以标记的图像。正如您所料,它存储在三个表中:

  • 图片
  • 标签
  • Tag_map(将图像映射到标签)

我有一个基于标签 ID 计算相关标签的 SQL 查询。该查询基本上检查使用该标签的图像的图像使用了哪些其他标签。示例:

Image1 标记为“熊”
Image2 标记为“熊”和“加拿大”

如果我在查询中抛出“Bear”(或其标签 ID),它将返回“Canada”。这工作正常。这是查询:

SELECT tag.name, tag.id, COUNT(tag_map.id) as cnt
FROM tag_map,tag
WHERE tag_map.tag_id = tag.id AND tag.id != '185' AND tag_map.image_id IN

    (SELECT tag_map.image_id FROM tag_map INNER JOIN tag ON tag_map.tag_id = tag.id WHERE tag.id = '185')

GROUP BY tag_map.id LIMIT 0,100

我坚持的部分是计数。对于返回的每个相关标签,我想知道该标签中有多少张图片。目前它总是返回 1,即使有例如 3。我试过计算不同的列都导致相同的输出,所以我想我的想法有缺陷。

【问题讨论】:

  • 请注意,'185' 只是一个硬编码的标签 ID,用于测试。

标签: sql mysql subquery


【解决方案1】:

您的代码无法正常工作,因为您只选择了“与选定标签相关联的图像”,而不是“与与选定标签相关联的图像相关联的标签相关联的图像”(我希望,我使用了正确的递归深度 :))。

您可以使用子选择来做到这一点:

SELECT tag.id, tag.name, COUNT(DISTINCT tag_map.image_id) as cnt
  FROM tag_map, tag
 WHERE tag_map.tag_id = tag.id
   AND tag.id != 185
   AND tag_map.tag_id IN (
     SELECT sub1.tag_id FROM tag_map AS sub1 WHERE sub1.image_id IN (
       SELECT sub2.image_id FROM tag_map AS sub2 WHERE sub2.tag_id = 185
     )
   )
GROUP BY tag.id, tag.name;

【讨论】:

  • 谢谢您,先生,效果很好。你摇滚,所以也一样。
  • 你不应该掷硬币来决定,你应该使用 mysql 'explain' 命令来检查哪个查询在你的表上效果更好。例如,在我的表配置中,Lieven 的查询要长一个子查询。
  • @Ferdy - 我没有运行 mysql,但 SQLServer 显示此解决方案的查询成本为 64%,我的解决方案为 36%...看图。
  • (应该是@dchkemarev)。
  • 如果可以的话,我会给你们两个硬币。请放心,你们都帮了我很大的忙,这就是重点。
【解决方案2】:

值得深思

  • 我注意到您在标签和图像表中使用了id,在 tag_map 表中使用了tablename_id。每个人都有自己的课外活动,但我发现如果一个 id 在任何地方都被命名为相同的名字,它会容易得多。我会将标签和图像中的 id 分别重命名为 tag_id 和 image_id。
  • 看来您的 id 是字符串。我冒昧地在示例中使用了整数。

以下示例使用 SQL Server。将 SQL 语句调整为 MySQL 应该不难。

测试数据

DECLARE @tag TABLE (id INTEGER, tag VARCHAR(32))
DECLARE @image TABLE (id INTEGER, image VARCHAR(32))
DECLARE @tag_map TABLE (image_id INTEGER, tag_id INTEGER)

INSERT INTO @tag
SELECT 185, 'Bear' 
UNION ALL SELECT 186, 'Canada'

INSERT INTO @image
SELECT 1, 'image1'
UNION ALL SELECT 2, 'image2'

INSERT INTO @tag_map
SELECT 1, 185
UNION ALL SELECT 2, 185
UNION ALL SELECT 2, 186

SQL 语句

SELECT  t.tag
        , t.id
        , cnt = (SELECT COUNT(*) FROM @tag_map WHERE tag_id = t.id)
FROM    @tag_map m
        INNER JOIN @tag t ON t.id = m.tag_id
        INNER JOIN (
          SELECT  m.image_id
          FROM    @tag_map m
          WHERE   m.tag_id = 185
        ) i ON i.image_id = m.image_id
WHERE   t.id <> 185

【讨论】:

  • 感谢您的详细回复。我将您的查询调整为 MySQL 语法,并将列名更改为我的表中使用的名称:SELECT t.name, t.id, COUNT(*) FROM tag_map as m INNER JOIN tag as t ON t.id = m.tag_id INNER JOIN ( SELECT m.image_id FROM tag_map as m WHERE m.tag_id = 185 ) as i ON i.image_id = m.image_id WHERE t.id 185 GROUP BY t.name, t.id 不幸的是,它仍然返回 1,它应该在哪里返回 3。我认为它正在计算相关标签的 n#,但我想计算具有该相关标签的图像#
  • @Ferdy,我已更改查询。你能验证结果吗?
  • 现在可以使用了,非常感谢。鉴于另一个答案,我现在有两个解决方案:) 我将掷硬币来决定谁赢。谢谢。
猜你喜欢
  • 2011-04-18
  • 1970-01-01
  • 2011-06-30
  • 2011-04-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-02
相关资源
最近更新 更多