Порахуйте кількість вхідних рядків у полі VARCHAR?


175

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

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

Я намагаюся розібратися, як повернути кількість разів, що виникає рядок у кожному з ОПИСУ.

Отже, якщо я хочу порахувати кількість разів, коли з'явиться значення, оператор 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()якщо ви використовуєте багатобайтові символи.
— inhan

На цю тему також відповіли тут
— Delickate

Привіт, як мені це зробити із запитом sqlserver?
— aintno12u

LENGTH ([поле]) - LENGTH (ЗАМІНА ([поле], '[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. Не потрібно округляти
— Нібріт

21

Трохи простіша та ефективніша версія рішення @yannis:

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

Різниця полягає в тому, що я замінюю рядок "value" на 1-char коротший рядок ("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 - LENGTH, а REPLACE - те саме.

Отже, еквівалентний запит у 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.