使用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
编辑:
作为一个起点,我知道:
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
答案 0 :(得分:3)
我会先写一个只返回我们想要返回的术语列表的查询来编写这个。例如:
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
有了它,我们可以进行连接操作以查找匹配的行,并获得计数。假设保证terms
不包含下划线(_
)或百分比(%
)字符,我们可以使用LIKE
比较。
鉴于我们列表中的每个术语至少会出现一次,我们可以使用内部联接。在更一般的情况下,我们可能期望返回零计数,我们将使用外连接。
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
在LIKE
比较中,百分号是通配符,匹配任何字符(零,一个或多个)。
如果terms
确实包含下划线或百分号字符,我们可以通过LIKE比较来逃避它们,因此不会将它们视为通配符。像这样的表达应该可以解决这个问题:
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
还有其他查询模式将返回指定的结果。这只是一种方法的示范。
注意:在问题的示例中,每个terms
是另一个terms
的子字符串,子字符串匹配出现在术语的开头。此查询还将查找术语不在开头的匹配项。
e.g。 dartboard
将被视为与art
可以修改查询以匹配仅出现在其他terms
的开头的terms
。
<强>后续强>
使用示例数据,返回:
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)
聚合外,我还在选择列表中包含了另一个表达式。这不是必需的,但它确实提供了一些关于哪些术语被认为是匹配的附加信息。
GROUP_CONCAT(DISTINCT c.terms ORDER BY c.terms) AS `matched_terms`
注意:如果terms
有可能包含反斜杠字符,我们也可以使用另一个REPLACE来转义这些字符
REPLACE(REPLACE(REPLACE( w.terms ,'\\','\\\\'),'_','\_'),'%','\%')
^^^^^^^^ ^^^^^^^^^^^^^