Contare il numero di occorrenze di una stringa in un campo VARCHAR?


175

Ho un tavolo come questo:

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

Sto cercando di capire come restituire il numero di volte in cui si verifica una stringa in ciascuna delle DESCRIZIONI.

Quindi, se voglio contare il numero di volte in cui appare 'valore', l'istruzione sql restituirà questo:

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

C'è un modo per fare questo? Non voglio usare php, solo mysql.


4
Le risposte di seguito ti porteranno lì. Tuttavia, non dimenticare di utilizzare CHAR_LENGTH()invece di LENGTH()utilizzare caratteri multibyte.
inhan,

Anche a questa discussione è stata data una risposta qui
Delickate

Ciao, come posso fare con la query sqlserver?
aintno12u,

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

Risposte:


343

Questo dovrebbe fare il trucco:

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

55
Questa soluzione è fantastica, proprio quello di cui avevo bisogno! Nota, tuttavia, che LENGTH () non è sicuro per più byte e potresti incorrere in strani errori. Usa invece CHAR_LENGTH () :)
nico gawenda,

1
non vi è alcuna differenza nell'uso di LENGTH()e CHAR_LENGTH()mentre è diviso nello stesso byte / carattere di conteggio. @nicogawenda
MohaMad

3
@chyupa ce l' undevaluehanno value, quindi dovrebbe essere contato. Se vuoi solo contare parole complete, forse devi cercare 'valore' o migliorare qualcosa di più complicato come usare regex.
PhoneixS,

2
Nota che ti imbatti in conteggi errati quando cerchi un testo che contiene anche parole con lettere maiuscole (come il tedesco in cui tutti i nomi sono scritti con lettere maiuscole). REPLACE sostituisce solo corrispondenze esatte. Per considerare tutte le parole è necessario modificare la sostituzione sopra in: LENGTH( REPLACE ( LOWER(description), "value", "") )e assicurarsi che "valore" sia sempre minuscolo utilizzando PHP strtolower(). PS: questa soluzione sopra mi ha aiutato a costruire il mio piccolo motore di ricerca e a ponderare i risultati in base al numero di parole all'interno del testo. Grazie!
Kai Noack,

2
Il ROUNDqui non è necessario. assumere una stringa di lunghezza xcon noccorrenze di 'value. LENGTH(description) - LENGTH( REPLACE ( description, "value", "") ) ti darà sempre n*length("value"), immersioni che per lunghezza di valore lasceranno sempre un numero intero n. Non c'è bisogno di arrotondare
Nibhrit

21

Variazione un po 'più semplice ed efficace della soluzione @yannis:

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

La differenza è che sostituisco la stringa "value" con una stringa più corta di 1 carattere ("1234" in questo caso). In questo modo non è necessario dividere e arrotondare per ottenere un valore intero.

Versione generalizzata (funziona per ogni ago):

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

1
+1 per l'idea, anche se generalmente preferisco ovvie implementazioni, cioè che non richiedono ulteriori spiegazioni, anche se sembrano meno eleganti.
not2savvy

19

prova questo:

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


Demo di SQL Fiddle


2
lunghezza non è binaria, usa char_length ()
luky

12

In SQL SERVER, questa è la risposta

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

Risultato

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

Non ho installato MySQL, ma sono rimasto sorpreso nel trovare l'equivalente di LEN è LENGTH mentre REPLACE è lo stesso.

Quindi dovrebbe essere la query equivalente in MySql

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

Per favore fatemi sapere se ha funzionato anche per voi in MySql.


3

Ecco una funzione che lo farà.

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

Grazie Yannis, la tua soluzione ha funzionato per me e qui sto condividendo la stessa soluzione per più parole chiave con ordine e limite.


1

Questa è la funzione mysql usando la tecnica spaziale (testata con 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)) );

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.