Php 在MySQL中按特定关键字对结果分组?
我有一个页面标记了多个标签,标签上有我正在搜索的关键字,有时它没有标记该关键字,所以当它有标签时,它将返回如下结果 质疑,Php 在MySQL中按特定关键字对结果分组?,php,mysql,group-by,tagging,sql-like,Php,Mysql,Group By,Tagging,Sql Like,我有一个页面标记了多个标签,标签上有我正在搜索的关键字,有时它没有标记该关键字,所以当它有标签时,它将返回如下结果 质疑, 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_ti
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
所以我必须使用分组方式来解决这个问题
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
尝试不在左联接中使用条件:
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
编辑:如果要获取页面标题包含“文章标题”的行,以及没有该标题但包含所需关键字的行,请使用此查询(建议使用@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_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
哎哟
我认为您的SQl查询非常奇怪
需要注意的几点:
- 对于SQL引擎来说,使用像“%foo%”这样的
条是非常困难的,他必须顺序扫描所有行并在列栏中搜索子字符串“foo”。索引用法不可用。所以,如果可以的话,尽量避免。如果可以,请至少使用类似于“foo%”的条。
。在您的情况下,您可能会有标题“article title 80”匹配的页面,您确定不只是需要一个p.page\u title='article title 8'
- 为什么要在order by指令中设置
+0
?是否确实要阻止使用索引
p.page\u hide!='1’
,p.page\u hide不是一个小玩意吗?是一根绳子吗?为什么使用UTF8编码字符存储0或1
但这不是问题所在
您的问题之一是,在SQL中使用GROUPBYGROUPBY p.page_id
实际上是错误的,但MySQL隐藏了这一事实。group by指令应至少包含SELECT部分中非聚集的每个元素(聚合是count或sum,或avg等)。在这里,你按id分组,得到一个随机的结果,MySQL认为你知道你在做什么,并且你确信当id相同时,select中的每个其他字段都是相同的(事实并非如此,标记名称不同)
如果你有几个标签匹配你的关键字('故事'在这里),你不想页面被列出几次吗?所有的标签
所以
您想选择一个有标签的页面。我会说使用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
对于第一个内部连接
,我只保留带有标记的页面。使用第二个内部连接
时,我只保留根页面
中的行,在根页面标签
中有一个匹配的标签。我认为您的NULL来自于此表中链接到其他不匹配标记的行(因此在root_tags表result中有NULL字段供您查询)因此,如果只需要匹配结果,请不要使用左连接
如果每个表只需要一个结果,则需要按p.page\u id、p.page\u name进行分组,并且需要在剩余字段t.tag\u name
上添加聚合函数。您可以使用GROUP\u CONTACT(t.tag\u name ORDER BY t.tag\u name ASC SEPARATOR“,”)
获取此表的所有匹配标记的列表
编辑
因此,事实上,您似乎想要标题匹配的页面,或者关键字匹配的页面。在这种情况下,您应该使用左连接
,并且您将拥有空值。如果结果中不需要标记,EXISTS关键字仍然是您最好的朋友,只需将和EXISTS
替换为或EXISTS
。这是最快的解决方案
如果在结果中需要匹配的标记,或者在没有标记时为NULL,则有2种解决方案。一个UNION
查询混合了对标题的简单查询和对带有内部连接的标记的查询,或者使用group\u CONCAT执行nice group by。如果不使用GROUP_CONCAT(如@Dmitry Teplyakov answer中所示),您可能会获得页面标题不匹配的结果,只有关键字,但tag_name字段将显示NULL,因为在查询中应用GROUP BY之前列出的第一个tag_行是一个NULL字段——页面为3个关键字,匹配的关键字不是查询中的第一个--
但在这里,我们按标签名称取消了您的订单。按tag_name排序意味着如果同一页与关键字多次匹配,您希望它出现在多行中。或者如果名称匹配且关键字也匹配。。。也许不是。所以实际上,联合查询解决方案可能更好。但关键的一点是,您应该在tag_name字段中解释您想要什么:-)这是我的初始查询,但我需要使此查询动态化,因为有该关键字的行,以及没有该关键字的行。这有意义吗?谢谢。如果是这样的话,那么如果您使用或代替和条件(p.page_title,如'%article title 8%'或t.tag_name,如'%story%'),只需修改上面提供的查询,您就可以从中获得动态结果谢谢你的提醒,德米特里!:-)非常感谢你的回复,雷吉勒罗。事实上,我得到了你的建议后,我的结果-见我的编辑上面。谢谢你的帮助!:-)@劳蒂亚姆科克:看我的编辑,我不确定你真的有你想要的。取决于你真正想要什么。在SQL中要小心那些似乎给出了正确结果的查询,进行扩展测试cases.regilero,感谢您的编辑。我将代码更改为使用内部连接
作为saf
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
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;