Как извлечь n-е слово и посчитать вхождения в строку MySQL - PullRequest
58 голосов
/ 26 октября 2010

Я хотел бы иметь запрос mysql, подобный этому:

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

Все примеры регулярных выражений в mysql используются для запроса соответствия текста выражению, но не для извлечения текста из выражения.Есть ли такой синтаксис?

Ответы [ 9 ]

45 голосов
/ 26 октября 2010

Ниже предлагается предлагаемое решение для специфической проблемы ОП (извлечение 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

27 голосов
/ 07 сентября 2012

Сокращенный вариант извлечения второго слова в предложении:

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

Документы MySQL для SUBSTRING_INDEX

14 голосов
/ 26 октября 2010

В соответствии с http://dev.mysql.com/ функция SUBSTRING использует начальную позицию, а затем длину, поэтому функция для второго слова будет обязательно:

SUBSTRING(sentence,LOCATE(' ',sentence),(LOCATE(' ',LOCATE(' ',sentence))-LOCATE(' ',sentence)))
7 голосов
/ 26 октября 2010

Нет, синтаксис для извлечения текста с использованием регулярных выражений отсутствует.Вы должны использовать обычные функции управления строками .

. В качестве альтернативы выберите все значение из базы данных (или первые n символов, если вас беспокоит слишком большая передача данных), а затем используйтерегулярное выражение на клиенте.

5 голосов
/ 18 августа 2016

Я использовал ответ Брендана Буллена в качестве отправной точки для аналогичной проблемы, с которой я столкнулся, - получить значение определенного поля в строке 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>'))
)
5 голосов
/ 19 августа 2013

Как уже говорили другие, mysql не предоставляет инструментов регулярных выражений для извлечения подстрок.Это не значит, что у вас их не может быть, хотя, если вы готовы расширить mysql с помощью пользовательских функций:

https://github.com/mysqludf/lib_mysqludf_preg

Это может не сильно помочь, если вы хотитераспространять ваше программное обеспечение, что является препятствием для установки вашего программного обеспечения, но для внутреннего решения это может быть целесообразным.

2 голосов
/ 26 октября 2010

Я не думаю, что это возможно.Вы можете использовать функцию SUBSTRING для извлечения нужной части.

0 голосов
/ 20 мая 2018

My домноженная функция замены регулярного выражения может использоваться для этого.

Демо

См. это демо 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.

0 голосов
/ 01 ноября 2012

Значение поля:

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