Подсчитать количество вхождений строки в поле VARCHAR?


175

У меня есть такая таблица:

TITLE          |   DESCRIPTION
------------------------------------------------
test1          |   value blah blah value
test2          |   value test
test3          |   test test test
test4          |   valuevaluevaluevaluevalue

Я пытаюсь выяснить, как вернуть количество раз, когда строка встречается в каждом из ОПИСАНИЕ.

Итак, если я хочу посчитать, сколько раз «value» появляется, оператор sql вернет это:

TITLE          |   DESCRIPTION                  |   COUNT
------------------------------------------------------------
test1          |   value blah blah value        |   2
test2          |   value test                   |   1
test3          |   test test test               |   0
test4          |   valuevaluevaluevaluevalue    |   5

Есть какой-либо способ сделать это? Я вообще не хочу использовать php, просто mysql.


4
Ответы ниже приведут вас туда. Тем не менее, не забудьте использовать CHAR_LENGTH()вместо, LENGTH()если вы используете многобайтовые символы.
Инхан

Эта тема также получила ответ здесь
Delickate

Привет, как я могу сделать это с запросом sqlserver?
aintno12u

ДЛИНА ([поле]) - ДЛИНА (ЗАМЕНА ([поле], '[char_to_find]', ''))
Феникс

Ответы:


343

Это должно сделать трюк:

SELECT 
    title,
    description,    
    ROUND (   
        (
            LENGTH(description)
            - LENGTH( REPLACE ( description, "value", "") ) 
        ) / LENGTH("value")        
    ) AS count    
FROM <table> 

55
Это отличное решение, именно то, что мне было нужно! Но обратите внимание, что LENGTH () не является многобайтовой безопасностью, и вы можете столкнуться со странными ошибками. Вместо этого используйте CHAR_LENGTH () :)
nico gawenda

1
нет разницы в использовании LENGTH()и CHAR_LENGTH()при разделении на один и тот же счетный байт / символ. @nicogawenda
MohaMad

3
У @chyupa undevalueесть valueэто так, это должно быть посчитано. Если вы хотите считать только полные слова, возможно, вам нужно найти «значение» или улучшить что-то более сложное, например, с помощью регулярных выражений.
PhoneixS

2
Обратите внимание, что при поиске в тексте, в котором также есть слова с заглавными буквами, встречаются неправильные значения (например, немецкий, где все существительные пишутся с заглавной буквы). ЗАМЕНА заменяет только точные совпадения. Чтобы рассмотреть все слова, вам нужно изменить замену выше на: LENGTH( REPLACE ( LOWER(description), "value", "") )и убедиться, что «значение» всегда в нижнем регистре с помощью PHP strtolower(). PS: это решение помогло мне создать собственную маленькую поисковую систему и взвесить результаты по количеству слов в тексте. Спасибо!
Кай Ноак

2
ROUNDЗдесь не нужно. принять строку длины xс nвхождениями 'value. LENGTH(description) - LENGTH( REPLACE ( description, "value", "") ) всегда даст вам n*length("value"), ныряя, что по длине значения всегда будет оставлять целое число n. Нет необходимости округлять
Nibhrit

21

Немного проще и эффективнее вариант решения @yannis:

SELECT 
    title,
    description,    
    CHAR_LENGTH(description) - CHAR_LENGTH( REPLACE ( description, 'value', '1234') ) 
        AS `count`    
FROM <table> 

Разница в том, что я заменяю строку «value» на более короткую строку на 1 символ (в данном случае «1234»). Таким образом, вам не нужно делить и округлять, чтобы получить целочисленное значение.

Обобщенная версия (работает для каждой игольной струны):

SET @needle = 'value';
SELECT 
    description,    
    CHAR_LENGTH(description) - CHAR_LENGTH(REPLACE(description, @needle, SPACE(LENGTH(@needle)-1))) 
        AS `count`    
FROM <table> 

1
+1 за идею, хотя я обычно предпочитаю очевидные реализации, то есть которые не требуют дополнительного объяснения, даже если они выглядят менее изящно.
not2savvy


12

В SQL SERVER это ответ

Declare @t table(TITLE VARCHAR(100), DESCRIPTION VARCHAR(100))

INSERT INTO @t SELECT 'test1', 'value blah blah value' 
INSERT INTO @t SELECT 'test2','value test' 
INSERT INTO @t SELECT 'test3','test test test' 
INSERT INTO @t SELECT 'test4','valuevaluevaluevaluevalue' 


SELECT TITLE,DESCRIPTION,Count = (LEN(DESCRIPTION) - LEN(REPLACE(DESCRIPTION, 'value', '')))/LEN('value') 

FROM @t

результат

TITLE   DESCRIPTION               Count
test1   value blah blah value        2
test2   value test                   1
test3   test test test               0
test4   valuevaluevaluevaluevalue    5

У меня не установлена ​​MySQL, но я обнаружил, что Эквивалент LEN - это ДЛИНА, а ЗАМЕНА - то же самое.

Таким образом, эквивалентный запрос в MySql должен быть

SELECT TITLE,DESCRIPTION, (LENGTH(DESCRIPTION) - LENGTH(REPLACE(DESCRIPTION, 'value', '')))/LENGTH('value') AS Count
FROM <yourTable>

Пожалуйста, дайте мне знать, если это работает для вас в MySql.


3

Вот функция, которая сделает это.

CREATE FUNCTION count_str(haystack TEXT, needle VARCHAR(32))
  RETURNS INTEGER DETERMINISTIC
  BEGIN
    RETURN ROUND((CHAR_LENGTH(haystack) - CHAR_LENGTH(REPLACE(haystack, needle, ""))) / CHAR_LENGTH(needle));
  END;

1
SELECT 
id,
jsondata,    
ROUND (   
    (
        LENGTH(jsondata)
        - LENGTH( REPLACE ( jsondata, "sonal", "") ) 
    ) / LENGTH("sonal")        
)
+
ROUND (   
    (
        LENGTH(jsondata)
        - LENGTH( REPLACE ( jsondata, "khunt", "") ) 
    ) / LENGTH("khunt")        
)
AS count1    FROM test ORDER BY count1 DESC LIMIT 0, 2

Спасибо Яннис, ваше решение сработало для меня, и здесь я делюсь тем же решением для нескольких ключевых слов с порядком и лимитом.


1

Это функция mysql, использующая космическую технику (протестирована с mysql 5.0 + 5.5): CREATE FUNCTION count_str( haystack TEXT, needle VARCHAR(32)) RETURNS INTEGER DETERMINISTIC RETURN LENGTH(haystack) - LENGTH( REPLACE ( haystack, needle, space(char_length(needle)-1)) );

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.