MySQL计数列中出现的子字符串数
使用MySQL,我试图计算每一行的子字符串在列中出现的次数 在下面的示例表中,字符串“art”在“术语”列中出现三次,因此其计数为3 示例表:MySQL计数列中出现的子字符串数,mysql,Mysql,使用MySQL,我试图计算每一行的子字符串在列中出现的次数 在下面的示例表中,字符串“art”在“术语”列中出现三次,因此其计数为3 示例表: TERMS art artistic painting elephant art deco paint paintings 期望输出: TERMS COUNT art 3 artistic 1 painting 2 elephant 1 art deco 1 paint 2 paintings 1
TERMS
art
artistic
painting
elephant
art deco
paint
paintings
期望输出:
TERMS COUNT
art 3
artistic 1
painting 2
elephant 1
art deco 1
paint 2
paintings 1
编辑:
作为起点,我知道:
SELECT terms, COUNT(*)
FROM table
GROUP BY terms
将输出每个完整术语字符串的出现次数。对于子字符串匹配,我认为这可能涉及子查询
尝试了以下操作,但每次计数均为1
SELECT terms, ROUND((CHAR_LENGTH(terms) - CHAR_LENGTH(REPLACE(terms, terms, ""))) / CHAR_LENGTH(terms)) AS count
FROM table
GROUP BY terms
我首先编写一个查询,返回我们想要返回的术语列表。例如:
SELECT t.terms
FROM `table` t
GROUP BY t.terms
然后将其包装在parens中,并将其用作内联视图
SELECT w.terms
FROM ( SELECT t.terms
FROM `table` t
GROUP BY t.terms
) w
ORDER BY w.terms
这样,我们就可以执行联接操作来查找匹配的行,并获得一个计数。假设保证术语
不包含下划线(\uu
)或百分比(%
)字符,我们可以使用类似于的比较
考虑到列表中的每个术语都将至少出现一次,我们可以使用内部联接。在更一般的情况下,我们可能希望返回零计数,我们将使用外部联接
SELECT w.terms
, COUNT(1) AS `COUNT`
FROM ( SELECT t.terms
FROM `table` t
GROUP BY t.terms
) w
JOIN `table` c
ON c.terms LIKE CONCAT('%', w.terms ,'%')
GROUP BY w.terms
ORDER BY w.terms
在与
类似的比较中,百分号是与任何字符(零、一个或多个)匹配的通配符
如果术语
可能包含下划线或百分比字符,我们可以对它们进行转义,这样它们就不会被类似的比较视为通配符。这样的表达式应该可以实现以下目的:
REPLACE(REPLACE( w.terms ,'_','\_'),'%','\%')
所以我们会有这样一个查询:
SELECT w.terms
, COUNT(1) AS `COUNT`
FROM ( SELECT t.terms
FROM `table` t
GROUP BY t.terms
) w
JOIN `table` c
ON c.terms LIKE CONCAT('%',REPLACE(REPLACE( w.terms ,'_','\_'),'%','\%'),'%')
GROUP BY w.terms
ORDER BY w.terms
还有其他将返回指定结果的查询模式。这只是一种方法的演示
注意:在问题中的示例中,每个
术语
都是另一个术语
的子字符串,子字符串匹配出现在术语的开头。此查询还将查找术语不在开头的匹配项
e、 g.dartboard
将被视为与art
可以修改查询以匹配仅出现在其他术语
开头的术语
跟进
对于示例数据,返回:
terms COUNT matched_terms
--------- -------- -------------------------
art 3 art,art deco,artistic
art deco 1 art deco
artistic 1 artistic
elephant 1 elephant
paint 3 paint,painting,paintings
painting 2 painting,paintings
paintings 1 paintings
除了COUNT(1)
aggregate之外,我还在select列表中包含了另一个表达式。这不是必需的,但它确实提供了一些关于哪些术语被认为是匹配项的附加信息
GROUP_CONCAT(DISTINCT c.terms ORDER BY c.terms) AS `matched_terms`
注意:如果terms
可能包含反斜杠字符,我们也可以使用另一个替换来转义这些字符
REPLACE(REPLACE(REPLACE( w.terms ,'\\','\\\\'),'_','\_'),'%','\%')
^^^^^^^^ ^^^^^^^^^^^^^
请与我们分享您的试用。您的替换功能可自行替换每行的术语;请看我答案中的建议1和建议2。非常好的答案!但是你不需要一个w.term
的分组吗?同样在ORDER BY
之前?@MichaelK:是的。我们确实需要一个小组。啊!(答案经过编辑以包含更正。)难以置信的答案!非常感谢。这不仅实现了我的目标,而且在研究你的答案时我学到了很多。我在一个有26k行的表上运行了它,查询用了175s才完成。@OBreaux1:LIKE与百分比通配符的比较要求检查表中的每一行,检查每个术语
条目。如果表中的行较长(表中的列较多),则索引。。。在表(术语)
上,如果完全通过索引满足查询,则可能会提高性能。@OBreaux1:此查询返回包含术语的行数;如果存在匹配项,则计数将递增1。例如,“dartmart”将匹配“art”,但计数将增加1。不是两个,即使“艺术”出现了两次。