Mysql 多次使用LEFT JOIN只能产生一行
它是一个基于智能标签的图像搜索系统。用户在这样的表中添加带有适当标记的图像:Mysql 多次使用LEFT JOIN只能产生一行,mysql,sql,join,left-join,outer-join,Mysql,Sql,Join,Left Join,Outer Join,它是一个基于智能标签的图像搜索系统。用户在这样的表中添加带有适当标记的图像: 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表中。(请注意,我在重复更新时使用了一个IN
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
查询。)
现在请考虑以下标签的图像:
,河流
(这是一张阳光明媚的河流图片)天
,河
(午夜月光下的那条河)夜
,树
天
,树
夜
,花
天
,花
夜
河流
,并显示带有标签河流的任何图像:在这种情况下,显示第一幅图像(由河流白天标记)和第二幅图像(由河流夜晚标记)。用户查看第二张图像(由河流和夜晚标记),并查看记录在表usertagview
中的图像
然后用户尝试新的搜索标签树
,并查看树夜
图像
我希望如果用户搜索鲜花
,那么鲜花之夜
将优先于鲜花之日
。我的意思是花之夜应该在花之日之前到来。换句话说,我需要一个查询,根据用户以前的视图列出由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
问题
我的查询中的**左连接**
与正常的内部连接没有区别。它们都有相同的结果。即使我使用了右连接
也不会有任何区别。您总是会得到表映像+内部连接映像标记的结果,而不考虑下一步/之后要连接什么。如果您想要更多的结果,那么您也需要左连接imagetag表。您的左连接的行为与内部连接的行为相同的原因是因为您的where
子句中有关于左连接的附加条件。这实际上将外部联接
转换为内部联接
这是因为如果usertagview.tag\u id
为NULL
,则在没有匹配记录的情况下,where
子句中的in
语句会删除带有NULL
值的行
要更正此问题,您可以将您的usertagview.tag\u id移动到…
签入您的加入的ON
子句中
然而,这只是你的一半问题。您只检查用户输入的特定标记的视图,但如果我了解您的实际需求,您希望检查与任何图像相关联的任何标记的视图,该图像具有与您的搜索词匹配的标记
例如,当用户输入flower
时,您希望首先找到标记有flower
的任何图像,然后检查视图中该组图像的所有其他标记
我相信以下查询可以实现这一点,并且:
这是一个常见的问题。幸运的是,这是一个很容易解决的问题
看到这个了吗
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\u id
。
因此,WHERE子句上的usertagview.tag_id IN(从…)中选择tag_id
基本上取消了左JOIN上的usertagview所取得的任何成功
因此,要修复您的查询,请将您的内部联接
-y usertagview恢复为左联接
一个,然后将usertagview条件改为联接条件:
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
那会解决的。如果不是(因为我不知道在您的表中,哪些是一对多,哪些是一对一,所以在本例中,我将抛出通常有效的方法),请尝试将内部联接imagetag
更改为左联接
。由于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无法理解您的意图;在这种情况下,需要将结果展平以获得正确的输出。下面是一个很好的演练,介绍如何使结果平坦化:谢谢,但是LEFT JOIN imagetag
也不起作用。换句话说,我有3个左连接,但这不是答案,+1,因为我根本不关心它的重要性。现在我应该做更多的工作。谢谢你:)太好了。现在它就像一个符咒。sqlfiddle也确实起到了作用,因为我不得不对它进行一些更改!我真的需要函数IFNULL
,我相信我应该学习更多关于高级查询功能的知识,就像您已经使用了两次imagetag
一样。有教学高级查询的网站/PDF吗?这对我真的很有帮助。因为我还没有深入理解您在查询中使用的逻辑。我会更感激任何先进的mysql查询教程或PDF。感谢you@smhnaji我认为你已经走上了正确的道路。。。在查询中,正确地使用了内部联接和外部联接。这个查询中唯一棘手的部分是两次加入同一个表,这是人们忘记的
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
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