【问题标题】:How to extract the nth word and count word occurrences in a MySQL string?如何提取 MySQL 字符串中的第 n 个单词并计算单词出现次数?
【发布时间】:2011-04-30 14:34:54
【问题描述】:

我想要一个这样的 mysql 查询:

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

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

【问题讨论】:

    标签: mysql regex word-count


    【解决方案1】:

    以下是针对 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 来定位。我不介意“接受的答案”,我只想提供帮助。
    • 可以让它更通用一点,不仅仅是空间,还可以添加 LENGTH 以匹配分隔符后面的值,例如LOCATE('&lt;string&gt; ', sentence) + STRLEN('&lt;string&gt;')
    • 它几乎是完美的,除了它实际上返回“IS”,这是不正确的。请在下面查看我的答案。
    • 我同意@HypolitePetovan,这个答案有点不正确,因为它返回 3 个字符而不是 2 个字符。它的位置也不正确。我建议进行编辑,包括添加 CHAR_LENGTH 以正确定位并确定正确的长度。使用空格但在整个选择上运行 CHAR_LENGTH 时很难显示它返回 3 个字符
    【解决方案2】:

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

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

    MySQL docs for SUBSTRING_INDEX

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

        【解决方案4】:

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

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

        【讨论】:

          【解决方案5】:

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

          https://github.com/mysqludf/lib_mysqludf_preg

          如果您想分发您的软件,这可能没有多大帮助,这会成为安装软件的障碍,但对于内部解决方案来说,这可能是合适的。

          【讨论】:

            【解决方案6】:

            我使用 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>'))
            )
            

            【讨论】:

              【解决方案7】:

              我认为这样的事情是不可能的。你可以使用SUBSTRING函数来提取你想要的部分。

              【讨论】:

                【解决方案8】:

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

                演示

                参见this DB-Fiddle demo,它返回著名十四行诗中的第二个单词(“I”)及其出现次数(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 (~) 字符替换。 注意:如果文本中可能出现波浪号,则可以选择不同的字符。

                然后使用this answer 中的技术将具有分隔值的字符串转换为单独的行值。它与来自 this answer 的巧妙技术相结合,用于生成由一系列递增数字组成的表格:在本例中为 0 - 10,000。

                【讨论】:

                  【解决方案9】:

                  该字段的值为:

                   "- 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%
                  

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 2016-06-28
                    • 2015-09-14
                    • 2011-02-07
                    • 1970-01-01
                    • 2014-04-29
                    • 2011-11-26
                    相关资源
                    最近更新 更多