【问题标题】:Multiple use of LEFT JOIN brings only 1 row多次使用 LEFT JOIN 只带来 1 行
【发布时间】:2012-05-10 18:05:55
【问题描述】:

它是一个智能标签库图像搜索系统。用户在这样的表中添加带有适当标签的图像:

image (id, title, ...)
tag (id, title) /* It doesn't matter who has created the tag*/
imagetag (image_id, tag_id) /* One image may have multiple tags */

用户查看图像,并且来自 *这些图像标签的访问* 记录在 usertagview 表中。 (请注意,我为此使用了 INSERT ON DUPLICATE UPDATE 查询。)

usertagview (user_id, tag_id, view_count)

现在请考虑一些带有以下标签的图片:

  • river,day(这是一张在阳光明媚的日子里展示河流的照片)
  • river, night(午夜月光下的那条河)
  • tree, day
  • tree, night
  • flower, day
  • flower, night

用户搜索标签 river 并显示任何带有标签 river 的图像:在这种情况下,第一张图像(由 river day 标记)和第二个(由河之夜标记)显示。用户查看第二张图片(标记为rivernight)并查看记录在表usertagview 中。

然后用户尝试重新搜索标签tree 并查看tree night 图像。

如果用户搜索flower,我希望flower night 优先于flower day。我的意思是flower night 应该在flower day 之前。换句话说,我想要一个查询,根据用户以前的视图列出由flower 标记的图像。 (flower night 首先,其他 flowers 下一个)。

我的查询失败:

SELECT

    DISTINCT (image.id) AS image_id,
    image.title AS image_title,
    SUM(usertagview.view_count) AS SUM_of_all_tag_views_for_each_image

FROM (image)

JOIN imagetag ON imagetag.image_id = image.id

**LEFT JOIN** usertagview ON
    usertagview.tag_id = imagetag.tag_id
    AND usertagview.user_id = {$user_id_from_php}

WHERE

    imagetag.tag_id IN ( {impolde(',', $array_of_id_of_tags_that_the_user_has_entered)} )
    AND
    usertagview.tag_id IN
        (SELECT tag_id FROM imagetag WHERE userimagetag.image_id = image.id)

ORDER BY SUM_of_all_tag_views_for_each_image DESC

问题

是不是我查询中的**LEFT JOIN**和普通的INNER JOIN没有区别。他们都有相同的结果。即使我使用 RIGHT JOIN 也没有区别。

【问题讨论】:

    标签: mysql sql join left-join outer-join


    【解决方案1】:

    无论您接下来/之后加入什么,您总是会得到您的表格图像 + INNER JOIN 图像标签的结果。如果您想要更多结果,您还需要 LEFT JOIN imagetag 表。

    【讨论】:

    • 谢谢,但LEFT JOIN imagetag 也不起作用。换句话说,我有 3 个LEFT JOINs。
    • 虽然这不是答案,但 +1 因为我根本不在乎它的重要性。现在我应该在这方面做更多的工作。还是谢谢你:)
    【解决方案2】:

    left join 的行为与inner join 相同的原因是因为您在where 子句中为left join 设置了附加条件。这实际上将您的outer join 变成了inner join

    这是因为如果在没有匹配记录的情况下usertagview.tag_idNULL,您的WHERE 子句中的IN 语句会消除具有NULL 值的行。

    要更正此问题,您可以将usertagview.tag_id IN ... 签入到您的联接的ON 子句中。

    但是,这只是您问题的一半。您只检查用户输入的特定标签的视图,但如果我了解您的实际要求,您希望检查视图中是否存在与任何具有与您的搜索词匹配的标签的图像相关联的标签.

    例如,当用户输入flower 时,您希望首先找到任何带有flower 标记的图像,然后检查该组图像的所有其他标记的视图。

    我相信下面的查询可以做到这一点,this SQL Fiddle shows the query in action:

    SELECT
      i.id AS image_id,
      i.title AS image_title,
      IFNULL(SUM(utv.view_count), 0) AS associated_view_totals
    FROM
      imagetag originalTag
      JOIN imagetag associatedTags 
        ON associatedTags.image_id = originalTag.image_id
      JOIN image i 
        ON i.id = associatedTags.image_id
      LEFT JOIN usertagview utv 
        ON utv.user_id = 1
        AND utv.tag_id = associatedTags.tag_id
    WHERE
      -- User searches for flower tag (Let's assume 5 == flower)...
      originalTag.tag_id IN (5)
    GROUP BY
      i.id,
      i.title
    ORDER BY 
      associated_view_totals DESC
    

    【讨论】:

    • 完美。它现在就像一个魅力。 sqlfiddle 也确实有帮助,因为我不得不稍微改变一下!我真的需要函数IFNULL,我相信我应该了解更多关于高级查询能力的信息,比如你使用过两次imagetag。任何用于教授高级查询的网站/PDF?这真的会帮助我。因为我还没有深入理解您在查询中使用的逻辑。我会更感激任何高级 mysql 查询教程或 PDF。谢谢
    • @smhnaji 我认为您已经走在正确的轨道上...在您的查询中,您正确地使用了内部联接与外部联接。此查询中唯一棘手的部分是您两次加入同一个表,这是人们可能忘记的。至于一个很好的参考,MySQL documentation is actually very helpful,也提供了很好的例子。
    【解决方案3】:

    这是一个常见问题。幸运的是,这是一个很容易解决的问题。

    看到了吗?

    LEFT JOIN usertagview ON
        usertagview.tag_id = imagetag.tag_id -- see this?
        AND usertagview.user_id = {$user_id_from_php}  
    
    WHERE
    
        imagetag.tag_id IN ( {impolde(',', $array_of_id_of_tags_that_the_user_has_entered)} )
        AND
    

    还有这个?

        usertagview.tag_id IN -- and this?
            (SELECT tag_id FROM imagetag WHERE userimagetag.image_id = image.id)
    

    两个条件共享同一个字段,即usertagview.tag_id。 因此,WHERE 子句中的usertagview.tag_id IN (SELECT tag_id FROM ...) 基本上抵消了LEFT JOINing imagetag 上的 usertagview 的任何成功。

    因此,要修复您的查询,请将您的 INNER JOIN-y usertagview 恢复为 LEFT JOIN 之一,然后将 usertagview 条件改为 JOIN 条件:

    SELECT
    
        DISTINCT (image.id) AS image_id,
        image.title AS image_title,
        SUM(usertagview.view_count) AS SUM_of_all_tag_views_for_each_image
    
    FROM (image)
    
    JOIN imagetag ON imagetag.image_id = image.id
    
    LEFT JOIN usertagview ON
        usertagview.tag_id = imagetag.tag_id
        AND usertagview.user_id = {$user_id_from_php}
    
        -- moved the WHERE condition here
        AND
        usertagview.tag_id IN
            (SELECT tag_id FROM imagetag WHERE userimagetag.image_id = image.id)
    
    
    WHERE
    
        imagetag.tag_id IN ( {impolde(',', $array_of_id_of_tags_that_the_user_has_entered)} )
    
    ORDER BY SUM_of_all_tag_views_for_each_image DESC
    

    这样就解决了。如果不是(因为我不知道你的桌子上是一对多的,还是一对一的,所以在这种情况下,我会扔掉 通常有效),尝试将INNER JOIN imagetag更改为LEFT JOIN。由于 WHERE 子句中的imagetag 条件将取消由LEFT JOIN 条件产生的任何行,因此将imagetag 条件从WHERE 子句也移至LEFT JOIN

    SELECT
    
        DISTINCT (image.id) AS image_id,
        image.title AS image_title,
        SUM(usertagview.view_count) AS SUM_of_all_tag_views_for_each_image
    
    FROM (image)
    
    LEFT JOIN imagetag ON imagetag.image_id = image.id
        -- WHERE clause condition moved here.
        -- WHERE conditionXXX basically cancels out whatever rows
        -- obtained from `LEFT JOIN ON conditionXXX`, in which conditionXXX share
        -- the same field.  IN this case, it is imagetag.
        AND    
        imagetag.tag_id IN ( {impolde(',', $array_of_id_of_tags_that_the_user_has_entered)} )
    
    
    LEFT JOIN usertagview ON
        usertagview.tag_id = imagetag.tag_id
        AND usertagview.user_id = {$user_id_from_php}
    
     -- moved here
        AND
        usertagview.tag_id IN
            (SELECT tag_id FROM imagetag WHERE userimagetag.image_id = image.id)
    
    
    
    ORDER BY SUM_of_all_tag_views_for_each_image DESC
    

    如果第二个建议仍未提供结果,则您的查询当前正在处理 多个 一对多表关系。如果查询中有多个一对多的表关系,SQL 无法弄清楚您的意图;在这种情况下,您需要展平结果以获得正确的输出。以下是关于如何展平结果的一个很好的演练:http://www.anicehumble.com/2012/05/sql-count-computer-program-does-what.html

    【讨论】:

      猜你喜欢
      • 2015-12-21
      • 1970-01-01
      • 2015-04-02
      • 2013-08-11
      • 1970-01-01
      • 1970-01-01
      • 2020-12-25
      • 1970-01-01
      • 2011-10-20
      相关资源
      最近更新 更多