Compter le nombre d'occurrences d'une chaîne dans un champ VARCHAR?

175

J'ai une table comme celle-ci:

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

J'essaie de comprendre comment renvoyer le nombre de fois qu'une chaîne se produit dans chacune des DESCRIPTION.

Donc, si je veux compter le nombre de fois que 'value' apparaît, l'instruction sql renverra ceci:

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

Y a-t-il un moyen de faire ça? Je ne veux pas du tout utiliser php, juste mysql.

Geekman
la source
4
Les réponses ci-dessous vous y mèneront. Cependant, n'oubliez pas d'utiliser à la CHAR_LENGTH()place de LENGTH()si vous utilisez des caractères multi-octets.
inhan
Ce fil a également reçu une réponse ici
Delickate
Salut, comment puis-je faire cela avec la requête sqlserver?
aintno12u
LENGTH ([field]) - LENGTH (REPLACE ([field], '[char_to_find]', ''))
Phoenix

Réponses:

343

Cela devrait faire l'affaire:

SELECT 
    title,
    description,    
    ROUND (   
        (
            LENGTH(description)
            - LENGTH( REPLACE ( description, "value", "") ) 
        ) / LENGTH("value")        
    ) AS count    
FROM <table> 
Yannis
la source
55
Cette solution est géniale, exactement ce dont j'avais besoin! Mais notez que LENGTH () n'est pas sécurisé sur plusieurs octets et que vous risquez de rencontrer des erreurs étranges. Utilisez CHAR_LENGTH () à la place :)
nico gawenda
1
il n'y a pas de différence dans l'utilisation de LENGTH()et en CHAR_LENGTH()étant divisé sur le même octet / caractère de comptage. @nicogawenda
MohaMad
3
@chyupa undevalueont valueen elle il doit être compté. Si vous ne voulez compter que des mots complets, vous devrez peut-être rechercher «valeur» ou mieux quelque chose de plus compliqué comme l'utilisation de regex.
PhoneixS
2
Notez que vous rencontrez des nombres erronés lorsque vous recherchez dans du texte contenant également des mots en majuscules (comme l'allemand où tous les noms sont écrits en majuscules). Le REMPLACER ne remplace que les correspondances exactes. Pour prendre en compte tous les mots, vous devez changer le remplacement ci-dessus en: LENGTH( REPLACE ( LOWER(description), "value", "") )et assurez-vous que "valeur" est toujours en minuscules en utilisant PHP strtolower(). PS: Cette solution ci-dessus m'a aidé à construire mon propre petit moteur de recherche et à pondérer les résultats par le nombre de mots dans le texte. Merci!
Kai Noack
2
Le ROUNDici est inutile. supposons une chaîne de longueur xavec des noccurrences de 'value. LENGTH(description) - LENGTH( REPLACE ( description, "value", "") ) vous donnera toujours n*length("value"), la plongée qui par longueur de valeur laissera toujours un nombre entier n. Pas besoin d'arrondir
Nibhrit
21

Une variante un peu plus simple et plus efficace de la solution @yannis:

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

La différence est que je remplace la chaîne "valeur" par une chaîne plus courte de 1 caractère ("1234" dans ce cas). De cette façon, vous n'avez pas besoin de diviser et d'arrondir pour obtenir une valeur entière.

Version généralisée (fonctionne pour chaque chaîne d'aiguille):

SET @needle = 'value';
SELECT 
    description,    
    CHAR_LENGTH(description) - CHAR_LENGTH(REPLACE(description, @needle, SPACE(LENGTH(@needle)-1))) 
        AS `count`    
FROM <table> 
gaborsch
la source
1
+1 pour l'idée, bien que je préfère généralement les implémentations évidentes, c'est-à-dire qui ne nécessitent pas d'explication supplémentaire, même si elles semblent moins élégantes.
not2savvy
19

essaye ça:

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


Démo SQL Fiddle

Joe G Joseph
la source
2
length n'est pas binaire sûr, utilisez char_length ()
luky
12

Dans SQL SERVER, c'est la réponse

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

Résultat

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

Je n'ai pas installé MySQL, mais j'ai cherché à trouver l'équivalent de LEN est LENGTH tandis que REPLACE est le même.

Ainsi, la requête équivalente dans MySql devrait être

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

S'il vous plaît laissez-moi savoir si cela a fonctionné pour vous dans MySql également.

Niladri Biswas
la source
3

Voici une fonction qui fera cela.

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;
Michaelbn
la source
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

Merci Yannis, votre solution a fonctionné pour moi et ici je partage la même solution pour plusieurs mots-clés avec ordre et limite.

Solution logicielle Trimantra
la source
1

Voici la fonction mysql utilisant la technique de l'espace (testée avec 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)) );

jfx
la source