我的网页标记了多个标签,其中包含我正在搜索的关键字,有时候它没有标记该关键字,所以当它有这个标签时,它会返回如下所示的结果,
查询,
SELECT*
FROM root_pages AS p
LEFT JOIN root_mm_pages_tags AS mm
ON mm.page_id = p.page_id
LEFT JOIN root_tags AS t
ON t.tag_id = mm.tag_id
AND t.tag_name LIKE '%story%'
WHERE p.page_title LIKE '%article title 8%'
AND p.page_hide != '1'
ORDER BY (t.tag_name+0) ASC
结果,
page_id page_url tag_name
17 article title 8 NULL
17 article title 8 NULL
17 article title 8 sys-rsv-story-1
所以我必须使用GROUP BY
来解决这个问题,
SELECT*
FROM root_pages AS p
LEFT JOIN root_mm_pages_tags AS mm
ON mm.page_id = p.page_id
LEFT JOIN root_tags AS t
ON t.tag_id = mm.tag_id
AND t.tag_name LIKE '%story%'
WHERE p.page_title LIKE '%article title 8%'
AND p.page_hide != '1'
GROUP BY p.page_id
ORDER BY (t.tag_name+0) ASC
并返回类似这样的内容,
page_id page_url tag_name
17 article title 8 NULL
但是我的结果是它有我正在搜索的关键字,
page_id page_url tag_name
17 article title 8 sys-rsv-story-1
那么,是否可以按关键字对结果进行分组?还是其他更好的查询来归档这个?
此外,如果该关键字不存在,不应该返回结果,但它仍然存在,
page_id page_url tag_name
17 article title 8 NULL
17 article title 8 NULL
修改
我的新解决方案,
SELECT*
FROM root_pages AS p
INNER JOIN root_mm_pages_tags AS mm
ON mm.page_id = p.page_id
INNER JOIN root_tags AS t
ON t.tag_id = mm.tag_id
WHERE p.page_title LIKE '%{group1}%'
AND t.tag_name LIKE '%story%'
AND p.page_hide != '1'
AND EXISTS (
SELECT page_url
FROM root_pages AS p
LEFT JOIN root_mm_pages_tags AS mm
ON mm.page_id = p.page_id
LEFT JOIN root_tags AS t
ON t.tag_id = mm.tag_id
WHERE page_url = 'article title 1d'
AND t.tag_name LIKE '%story%'
AND p.page_hide != '1'
)
ORDER BY (t.tag_name+0) ASC
答案 0 :(得分:2)
尽量不要在LEFT JOIN中使用条件:
SELECT *
FROM root_pages AS p
LEFT JOIN root_mm_pages_tags AS mm
ON mm.page_id = p.page_id
LEFT JOIN root_tags AS t
ON t.tag_id = mm.tag_id
WHERE p.page_title LIKE '%article title 8%'
AND p.page_hide != '1'
AND t.tag_name LIKE '%story%'
GROUP BY p.page_id
ORDER BY (t.tag_name+0) ASC
编辑:如果您要获取页面标题包含“文章标题”的行以及没有该标题但需要关键字的行,请使用此查询(As @ user985935建议):
SELECT *
FROM root_pages AS p
LEFT JOIN root_mm_pages_tags AS mm
ON mm.page_id = p.page_id
LEFT JOIN root_tags AS t
ON t.tag_id = mm.tag_id
WHERE (p.page_title LIKE '%article title 8%'
OR t.tag_name LIKE '%story%')
AND p.page_hide != '1'
GROUP BY p.page_id
ORDER BY (t.tag_name+0) ASC
答案 1 :(得分:1)
Oucha。
我认为你的SQl查询很奇怪。
需要注意几件事:
bar LIKE '%foo%'
对于SQL引擎非常困难,他必须顺序扫描所有行并搜索列栏中的子字符串'foo'。索引使用不可用。如果可以,请避免使用它。如果可以,请至少使用bar LIKE 'foo%'
(如果您有开始,则索引可用)。在你的情况下你可以有一个标题'文章标题80'匹配的页面,你确定你不需要p.page_title = 'article title 8'
吗?+0
?你真的想阻止索引使用吗?p.page_hide != '1'
,p.page_hide不是一个小小的?这是一个字符串?为什么使用UTF8编码的字符来存储0或1?但这不是问题。
你的一个问题是,GROUP BY p.page_id
使用一个组实际上在SQL中是错误的,但是MySQL隐藏了这个事实。按指令分组应至少包含SELECT部分中不是aggegate的每个元素(聚合是count或sum,或avg等)。在这里你按ID分组,你得到一个随机的东西,MySQL认为你知道你正在做什么,并且你确定当id相同时,select中的每个其他字段都是相同的(不是这样的,tag_name不同)。
如果您有多个与您的关键字匹配的标签(此处为“故事”),您是否希望多次列出该页面?所有标签?
所以
您想要选择一个有标签的页面。我会说使用EXISTS
关键字并简化操作。
可能是这样的:
SELECT *
FROM root_pages AS p
WHERE p.page_title = 'article title 8'
AND p.page_hide != 1
-- exists will return true as soon as the engine find one matching row
AND EXISTS (
SELECT mm.page_id
FROM root_mm_pages_tags AS mm
LEFT JOIN root_tags AS t
ON t.tag_id = mm.tag_id
-- here we make a correlation between the subquery and the main query
WHERE mm.page_id = p.page_id
AND t.tag_name LIKE '%story%'
)
但是使用此查询,您只能获取页面名称,而不是标记结果。如果你想列出页面的所有匹配标签,你需要另一个查询,非常接近你所拥有的:
SELECT p.page_id, p.page_name, t.tag_name
FROM root_pages AS p
INNER JOIN root_mm_pages_tags AS mm
ON mm.page_id = p.page_id
INNER JOIN root_tags AS t
ON (t.tag_id = mm.tag_id
AND t.tag_name LIKE '%story%')
WHERE p.page_title = 'article title 8'
AND p.page_hide != 1
第一个INNER JOIN
我只保留有标签的页面。使用第二个INNER JOIN
我只保留root_mm_pages
中root_tags
中具有匹配标记的行。我认为你的NULL来自这个表中与其他不匹配标签链接的行(因此在root_tags表中有NULL字段可以查询)。 因此,如果您只想要匹配结果,请不要使用LEFT JOIN。
如果每个表只需要一个结果,则需要GROUP BY p.page_id, p.page_name
,并且需要在剩余字段t.tag_name
上添加聚合函数。您可以使用GROUP_CONTACT(t.tag_name ORDER BY t.tag_name ASC SEPARATOR ",")
获取此表的所有匹配标记的列表。
修改强>
因此,实际上您希望页面匹配标题 OR 页面与匹配关键字匹配。在这种情况下,您应该使用LEFT JOIN
,并且您将具有NULL值。如果结果中不需要标记,则EXISTS关键字仍然是您最好的朋友,只需将AND EXISTS
替换为OR EXISTS
即可。这是最快的解决方案。
如果您需要结果中的匹配标记,或者当没有标记时需要NULL,则您有2个解决方案。 UNION
查询混合来自对标题的简单查询和对具有内部联接的标记的查询,或者使用GROUP_CONCAT执行nice组。如果您不使用GROUP_CONCAT(如@Dmitry Teplyakov答案),您可能会获得页面标题不匹配的结果,只有关键字,但tag_name字段将显示NULL作为应用GROUP BY之前列出的第一个tag_row在查询上是一个NULL字段 - 该页面为3个关键字,匹配关键字不是查询中的第一个 - 。
SELECT
p.page_id,
p.page_name,
GROUP_CONCAT(t.tag_name ORDER BY t.tag_name ASC SEPARATOR ",")
FROM root_pages AS p
LEFT JOIN root_mm_pages_tags AS mm
ON mm.page_id = p.page_id
LEFT JOIN root_tags AS t
ON t.tag_id = mm.tag_id
WHERE p.page_hide != 1
AND (p.page_title = 'article title 8'
OR t.tag_name LIKE '%story%')
GROUP BY p.page_id, p.page_name;
但是这里我们通过tag_name松开你的订单。按tag_name排序意味着如果多次匹配关键字,则希望同一页面出现在多行中。或者,如果名称匹配,关键字也是......或者可能不是。事实上,UNION查询解决方案可能更好。但关键是你应该在tag_name字段中解释你想要的东西: - )
答案 2 :(得分:0)
这是我在评论中提到的示例查询:
SELECT *
FROM root_pages AS p
LEFT JOIN root_mm_pages_tags AS mm
ON mm.page_id = p.page_id
LEFT JOIN root_tags AS t
ON t.tag_id = mm.tag_id
WHERE p.page_hide != '1'
AND (t.tag_name LIKE '%story%' OR p.page_title LIKE '%article title 8%')
GROUP BY p.page_id
ORDER BY (t.tag_name+0) ASC