Policzyć liczbę wystąpień ciągu w polu VARCHAR?


175

Mam taki stół:

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

Próbuję dowiedzieć się, jak zwrócić liczbę wystąpień ciągu w każdym z OPISÓW.

Tak więc, jeśli chcę policzyć, ile razy pojawia się `` wartość '', instrukcja sql zwróci to:

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

Czy jest na to sposób? W ogóle nie chcę używać php, tylko mysql.


4
Odpowiedzi poniżej zaprowadzą Cię tam. Nie zapomnij jednak użyć CHAR_LENGTH()zamiast, LENGTH()jeśli używasz znaków wielobajtowych.
inhan

Na ten wątek również odpowiedziano tutaj
Delickate

Cześć, jak to zrobić za pomocą zapytania sqlserver?
aintno12u

LENGTH ([pole]) - LENGTH (REPLACE ([field], '[char_to_find]', ''))
Phoenix

Odpowiedzi:


343

To powinno załatwić sprawę:

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

55
To rozwiązanie jest niesamowite, właśnie tego potrzebowałem! Pamiętaj jednak, że LENGTH () nie jest bezpieczna dla wielu bajtów i możesz napotkać dziwne błędy. Zamiast tego użyj CHAR_LENGTH () :)
nico gawenda

1
nie ma różnicy w używaniu LENGTH()i CHAR_LENGTH()podczas dzielenia na ten sam licznik bajtów / znaków. @nicogawenda
MohaMad

3
@chyupa undevaluema valuew niej więc to należy policzyć. Jeśli chcesz liczyć tylko całe słowa, być może musisz wyszukać „wartość” lub lepiej coś bardziej skomplikowanego, na przykład użycie wyrażenia regularnego.
PhoneixS

2
Zwróć uwagę, że podczas przeszukiwania tekstu, który zawiera również słowa pisane wielką literą, napotkasz błędne liczenie (jak w języku niemieckim, gdzie wszystkie rzeczowniki są pisane wielką literą). REPLACE zastępuje tylko dokładne dopasowania. Aby wziąć pod uwagę wszystkie słowa, musisz zmienić powyższe zastąpienie na: LENGTH( REPLACE ( LOWER(description), "value", "") )i upewnij się, że „wartość” jest zawsze pisana małą literą, używając PHP strtolower(). PS: Powyższe rozwiązanie pomogło mi zbudować własną małą wyszukiwarkę i zważyć wyniki według liczby słów w tekście. Dzięki!
Kai Noack

2
ROUNDTutaj jest zbędne. załóż ciąg długości xz nwystąpieniami 'value. LENGTH(description) - LENGTH( REPLACE ( description, "value", "") ) zawsze da ci n*length("value"), nurkowanie, które według długości zawsze pozostawi liczbę całkowitą n. Nie trzeba
kończyć

21

Nieco prostsza i bardziej efektywna odmiana rozwiązania @yannis:

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

Różnica polega na tym, że zastępuję ciąg „wartość” krótszym łańcuchem o 1 znaku (w tym przypadku „1234”). W ten sposób nie musisz dzielić i zaokrąglać, aby uzyskać wartość całkowitą.

Wersja uogólniona (działa dla każdej igły):

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

1
+1 do pomysłu, choć generalnie preferuję implementacje oczywiste, tj. Niewymagające dodatkowych wyjaśnień, nawet jeśli wyglądają mniej elegancko.
not2savvy

19

Spróbuj tego:

 select TITLE,
        (length(DESCRIPTION )-length(replace(DESCRIPTION ,'value','')))/5 as COUNT 
  FROM <table> 


SQL Fiddle Demo


2
length nie jest bezpieczna binarnie, użyj char_length ()
luky

12

W SQL SERVER to jest odpowiedź

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

Wynik

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

Nie mam instalacji MySQL, ale przeszukałem go, aby znaleźć odpowiednik LEN to LENGTH, podczas gdy REPLACE jest takie samo.

Zatem równoważne zapytanie w MySql powinno brzmieć

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

Daj mi znać, jeśli to zadziałało również w MySql.


3

Oto funkcja, która to zrobi.

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

Dzięki Yannis, Twoje rozwiązanie zadziałało dla mnie i tutaj udostępniam to samo rozwiązanie dla wielu słów kluczowych z kolejnością i limitem.


1

Oto funkcja mysql wykorzystująca technikę kosmiczną (testowana z 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)) );

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.