Как извлечь n-е слово и посчитать вхождения слов в строке MySQL?
Я хотел бы иметь запрос MySQL, как это:
select <second word in text> word, count(*) from table group by word;
Все примеры регулярных выражений в mysql используются для запроса соответствия текста выражению, но не для извлечения текста из выражения. Есть ли такой синтаксис?
9 ответов
Ниже предлагается предлагаемое решение для конкретной проблемы OP (извлечение 2-го слова строки), но следует отметить, что, поскольку состояния ответа 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 символов, если вас беспокоит слишком большая передача данных), а затем используйте регулярное выражение на клиенте.
Я использовал ответ Брендана Буллена в качестве отправной точки для решения аналогичной проблемы, которая заключалась в том, чтобы получить значение определенного поля в строке JSON. Однако, как я прокомментировал его ответ, он не совсем точен. Если ваша левая граница не просто пробел, как в оригинальном вопросе, расхождение увеличивается.
Исправленное решение:
SUBSTRING(
sentence,
LOCATE(' ', sentence) + 1,
LOCATE(' ', sentence, (LOCATE(' ', sentence) + 1)) - LOCATE(' ', sentence) - 1
)
Два различия - это +1 в параметре индекса SUBSTRING и -1 в параметре длины.
Для более общего решения "найти первое вхождение строки между двумя указанными границами":
SUBSTRING(
haystack,
LOCATE('<leftBoundary>', haystack) + CHAR_LENGTH('<leftBoundary>'),
LOCATE(
'<rightBoundary>',
haystack,
LOCATE('<leftBoundary>', haystack) + CHAR_LENGTH('<leftBoundary>')
)
- (LOCATE('<leftBoundary>', haystack) + CHAR_LENGTH('<leftBoundary>'))
)
Как уже говорили другие, mysql не предоставляет инструментов регулярных выражений для извлечения подстрок. Это не значит, что их у вас не может быть, если вы готовы расширить mysql с помощью пользовательских функций:
https://github.com/mysqludf/lib_mysqludf_preg
Это может не сильно помочь, если вы хотите распространять свое программное обеспечение, что является препятствием для установки вашего программного обеспечения, но для внутреннего решения это может быть целесообразным.
Я не думаю, что это возможно. Вы можете использовать функцию подстроки, чтобы извлечь нужную часть.
Моя доморощенная функция замены регулярных выражений может быть использована для этого.
демонстрация
Посмотрите эту демонстрацию 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 используется несколько приемов, и требуется некоторая аккредитация. Во-первых, заменитель регулярного выражения используется для замены всех непрерывных блоков несловесных символов, каждый из которых заменяется одной тильдой (~
) персонаж. Примечание. Вместо этого можно выбрать другой символ, если в тексте есть вероятность появления тильды.
Техника из этого ответа затем используется для преобразования строки с разделенными значениями в отдельные значения строки. Он комбинируется с умным приемом из этого ответа для генерации таблицы, состоящей из последовательности увеличивающихся чисел: в данном случае 0 - 10000.
Значение поля:
"- 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%