4

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

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)

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

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

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

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

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

我的查询失败:

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它也没有区别。

4

3 回答 3

4

left join的行为与 an 相同的原因是你在你的条款中inner join有额外的标准。这基本上将你变成了一个.left joinwhereouter joininner join

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

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

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

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

我相信以下查询可以完成此操作,并且此 SQL Fiddle 显示了正在执行的查询

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
于 2012-05-03T22:28:40.913 回答
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。因此,usertagview.tag_id IN (SELECT tag_id FROM ...)在您的 WHERE 子句中,基本上取消了 usertagview on LEFT JOINing imagetag 所具有的任何成功。

因此,要修复您的查询,请将您的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 imagetagLEFT JOIN。由于imagetagWHERE 子句中的条件将取消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

于 2012-05-03T23:05:25.613 回答
1

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

于 2012-05-01T08:34:18.133 回答