这是一个智能标签基础图像搜索系统。用户在这样的表格中添加带有适当标签的图像:
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
和night
标记)并查看表格usertagview
。
然后,用户尝试对标记tree
进行新搜索,并查看tree night
图片。
我希望如果用户搜索flower
,则flower night
优先于flower day
。我的意思是flower night
应该出现在flower day
之前。换句话说,我想要一个查询,根据用户之前的视图列出flower
标记的图像。 ( flower night
首先,其他flower
下一个)。
我的查询失败了:
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
,它也没有区别。
答案 0 :(得分:4)
您的left join
行为与inner join
相同的原因是因为您的left join
子句中的where
有其他条件。这基本上会将您的outer join
变为inner join
。
这样做的原因是,如果usertagview.tag_id
在没有匹配记录的情况下为NULL
,则IN
子句中的WHERE
语句将删除该行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
答案 1 :(得分: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 JOIN
图像标签上使用的任何成功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
as好吧:
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
答案 2 :(得分:1)
你总是得到你的桌面图像+ INNER JOIN imagetag的结果,没有你加入的下一个/之后的内容。如果你想要更多的结果,你需要LEFT JOIN imagetag表。