数据库
首页 > 数据库> > php-通过MySQL中的特定关键字对结果进行分组?

php-通过MySQL中的特定关键字对结果进行分组?

作者:互联网

我的网页上有多个带有我正在搜索的关键字的标签,有时它没有使用该关键字进行标签,因此当它具有该标签时,它将在下面返回类似这样的结果,

查询,

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

解决方法:

哎uch

我认为您的SQl查询非常奇怪.

需要注意的几件事:

>对于SQL引擎,使用栏LIKE’%foo%’非常困难,他必须顺序扫描所有行并在列栏中搜索子字符串’foo’.索引用法不可用.因此,如果可以,请避免使用它.如果可以的话,至少使用bar LIKE’foo%'(如果有开始就可以使用索引).而且,如果您的页面标题匹配“ article title 80”,您确定不只是需要p.page_title =“ article title 8”吗?
>为什么您按指令将顺序设为0?您真的要防止使用索引吗?
> p.page_hide!=’1′,p.page_hide不是tinyint吗?这是一个字符串吗?为什么使用UTF8编码的字符存储0或1?

但这不是问题.

您的问题之一是在SQL中使用GROUP BY p.page_id分组实际上是错误的,但是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“,”)获得该表所有匹配标签的列表.

编辑

因此,实际上您似乎想要标题匹配的页面或关键字匹配的页面.在这种情况下,您应该使用LEFT JOIN,并且您将拥有NULL值.如果结果中不需要标记,则EXISTS关键字仍然是您最好的朋友,只需将AND EXISTS替换为OR EXISTS.这是最快的解决方案.

如果结果中需要匹配的标签,或者当它们不是标签时需要NULL,则有2个解决方案. UNION查询混合了来自标题的简单查询和具有内部联接的标签查询的结果,或者通过GROUP_CONCAT进行了很好的分组.如果不使用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字段中解释您想要的内容:-)

标签:tagging,sql-like,mysql,php,group-by
来源: https://codeday.me/bug/20191202/2085919.html