如何在MySQL字符串中提取第n个单词并计算单词出现次数?

时间:2010-10-26 07:24:34

标签: mysql regex word-count

我想有一个像这样的mysql查询:

select <second word in text> word, count(*) from table group by word;

mysql中的所有正则表达式示例用于查询文本是否与表达式匹配,但不用于从表达式中提取文本。有没有这样的语法?

9 个答案:

答案 0 :(得分:44)

以下是针对OP的特定问题(提取字符串的第二个字)的建议解决方案,但应注意,作为mc0e的答案状态,实际上不提取正则表达式匹配在MySQL中开箱即用。如果你真的需要这个,那么你的选择基本上是1)在客户端上进行后处理,或2)安装MySQL扩展来支持它。


BenWells几乎是正确的。根据他的代码,这是一个稍微调整的版本:

SUBSTRING(
  sentence,
  LOCATE(' ', sentence) + CHAR_LENGTH(' '),
  LOCATE(' ', sentence,
  ( LOCATE(' ', sentence) + 1 ) - ( LOCATE(' ', sentence) + CHAR_LENGTH(' ') )
)

作为一个工作示例,我使用了:

SELECT SUBSTRING(
  sentence,
  LOCATE(' ', sentence) + CHAR_LENGTH(' '),
  LOCATE(' ', sentence,
  ( LOCATE(' ', sentence) + 1 ) - ( LOCATE(' ', sentence) + CHAR_LENGTH(' ') )
) as string
FROM (SELECT 'THIS IS A TEST' AS sentence) temp

这成功地提取了单词IS

答案 1 :(得分:27)

提取句子中第二个单词的缩短选项:

SELECT SUBSTRING_INDEX(SUBSTRING_INDEX('THIS IS A TEST', ' ',  2), ' ', -1) as FoundText

MySQL docs for SUBSTRING_INDEX

答案 2 :(得分:14)

根据http://dev.mysql.com/,SUBSTRING函数使用起始位置然后长度,所以第二个单词的函数肯定是:

SUBSTRING(sentence,LOCATE(' ',sentence),(LOCATE(' ',LOCATE(' ',sentence))-LOCATE(' ',sentence)))

答案 3 :(得分:7)

不,没有使用正则表达式提取文本的语法。你必须使用普通的string manipulation functions

或者从数据库中选择整个值(如果您担心过多的数据传输,则选择前n个字符),然后在客户端上使用正则表达式。

答案 4 :(得分:5)

正如其他人所说,mysql不提供用于提取子字符串的正则表达式工具。如果您准备使用用户定义的函数扩展mysql,那并不是说您无法拥有它们:

https://github.com/mysqludf/lib_mysqludf_preg

如果你想分发你的软件,这可能没什么帮助,但是对于安装你的软件来说是一个障碍,但是对于内部解决方案来说这可能是合适的。

答案 5 :(得分:5)

我使用Brendan Bullen的答案作为我遇到的类似问题的起点,即在JSON字符串中检索特定字段的值。但是,就像我评论他的回答一样,这并不完全准确。如果您的左边界不仅仅是原始问题中的空间,则差异会增加。

更正解决方案:

SUBSTRING(
    sentence,
    LOCATE(' ', sentence) + 1,
    LOCATE(' ', sentence, (LOCATE(' ', sentence) + 1)) - LOCATE(' ', sentence) - 1
)

两个差异是SUBSTRING索引参数中的+1和长度参数中的-1。

对于“在两个提供的边界之间找到字符串的第一次出现”的更一般的解决方案:

SUBSTRING(
    haystack,
    LOCATE('<leftBoundary>', haystack) + CHAR_LENGTH('<leftBoundary>'),
    LOCATE(
        '<rightBoundary>',
        haystack,
        LOCATE('<leftBoundary>', haystack) + CHAR_LENGTH('<leftBoundary>')
    )
    - (LOCATE('<leftBoundary>', haystack) + CHAR_LENGTH('<leftBoundary>'))
)

答案 6 :(得分:2)

我不认为这样的事情是可能的。您可以使用子字符串函数来提取所需的部分。

答案 7 :(得分:0)

我的home-grown regular expression replace function可用于此目的。

<强>演示

参见this DB-Fiddle demo,它从着名的十四行诗中返回第二个单词(&#34; I&#34;)及其出现次数(1)。

<强> SQL

假设正在使用MySQL 8或更高版本(允许使用Common Table Expression),以下内容将返回第二个单词及其出现次数:

WITH cte AS (
     SELECT digits.idx,
            SUBSTRING_INDEX(SUBSTRING_INDEX(words, '~', digits.idx + 1), '~', -1) word
     FROM
     (SELECT reg_replace(UPPER(txt),
                         '[^''’a-zA-Z-]+',
                         '~',
                         TRUE,
                         1,
                         0) AS words
      FROM tbl) delimited
     INNER JOIN
     (SELECT @row := @row + 1 as idx FROM 
      (SELECT 0 UNION ALL SELECT 1 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) t1,
      (SELECT 0 UNION ALL SELECT 1 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) t2, 
      (SELECT 0 UNION ALL SELECT 1 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) t3, 
      (SELECT 0 UNION ALL SELECT 1 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) t4, 
      (SELECT @row := -1) t5) digits
     ON LENGTH(REPLACE(words, '~' , '')) <= LENGTH(words) - digits.idx)
SELECT c.word,
       subq.occurrences
FROM cte c
LEFT JOIN (
  SELECT word,
         COUNT(*) AS occurrences
  FROM cte
  GROUP BY word
) subq
ON c.word = subq.word
WHERE idx = 1; /* idx is zero-based so 1 here gets the second word */

<强>解释

上面的SQL中使用了一些技巧,需要一些认证。首先,正则表达式替换器用于替换所有连续的非单词字符块 - 每个字符由单个tilda(~)字符替换。 注意:如果文本中出现tilda的可能性,则可以选择不同的字符。

然后使用来自this answer的技术将带有分隔值的字符串转换为单独的行值。它结合了来自this answer的聪明技术,用于生成一个由递增数字序列组成的表:在这种情况下为0 - 10,000。

答案 8 :(得分:-3)

该字段的值为:

 "- DE-HEB 20% - DTopTen 1.2%"
SELECT ....
SUBSTRING_INDEX(SUBSTRING_INDEX(DesctosAplicados, 'DE-HEB ',  -1), '-', 1) DE-HEB ,
SUBSTRING_INDEX(SUBSTRING_INDEX(DesctosAplicados, 'DTopTen ',  -1), '-', 1) DTopTen ,

FROM TABLA 

结果是:

  DE-HEB       DTopTEn
    20%          1.2%