我想要一个像这样的mysql查询:
select <second word in text> word, count(*) from table group by word;
mysql中的所有正则表达式示例都是用于查询文本是否与表达式匹配,而不是从表达式中提取文本。有这样的语法吗?
以下是针对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
提取句子中第二个单词的更短选项:
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX('THIS IS A TEST', ' ', 2), ' ', -1) as FoundText
根据 http://dev.mysql.com/ SUBSTRING 函数使用起始位置然后是长度,所以第二个单词的函数肯定是:
SUBSTRING(sentence,LOCATE(' ',sentence),(LOCATE(' ',LOCATE(' ',sentence))-LOCATE(' ',sentence)))
不,没有使用正则表达式提取文本的语法。您必须使用普通的字符串操作函数。
或者从数据库中选择整个值(如果担心数据传输过多,则选择前 n 个字符),然后在客户端上使用正则表达式。
正如其他人所说,mysql不提供用于提取子字符串的正则表达式工具。这并不是说如果您准备使用用户定义的函数扩展 mysql,您就不能拥有它们:
https://github.com/mysqludf/lib_mysqludf_preg
如果您想分发软件,这可能没有多大帮助,因为这会成为安装软件的障碍,但对于内部解决方案来说,这可能是合适的。
我使用 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>'))
)
我认为这样的事情是不可能的。您可以使用
SUBSTRING
功能提取您想要的部分。
我的自制正则表达式替换功能可以用于此目的。
演示
参见 这个 DB-Fiddle 演示,它返回著名十四行诗中的第二个单词(“I”)及其出现次数 (1)。
SQL
假设使用 MySQL 8 或更高版本(以允许使用公用表表达式),以下将返回第二个单词及其出现次数:
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 (
~
) 字符替换。 注意:如果文本中可能出现蒂尔达,可以选择其他字符。
然后使用这个答案中的技术将具有分隔值的字符串转换为单独的行值。它与这个答案中的巧妙技术相结合,用于生成一个由递增数字序列组成的表:在本例中为 0 - 10,000。
"- 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%