Comment extraire le nième mot et compter les occurrences de mot dans une chaîne MySQL?

j'aimerais avoir une requête mysql comme celle-ci:

select <second word in text> word, count(*) from table group by word;

Tous les regex exemples dans mysql sont utilisés pour interroger si le texte correspond à l'expression, mais pas pour extraire du texte d'une expression. Est-il une telle syntaxe?

58
demandé sur Steve Chambers 2010-10-26 11:24:34

9 réponses

ce qui suit est une solution proposée pour le problème spécifique de L'OP (extraction du 2ème mot d'une chaîne de caractères), mais il convient de noter que, comme la réponse de mc0e l'indique, l'extraction des correspondances regex n'est pas supportée dans MySQL. Si vous avez vraiment besoin de cela, alors vos choix sont essentiellement de 1) le faire dans le post-traitement sur le client, ou 2) installer une extension MySQL pour le soutenir.


Benwell l'a très presque correct. A partir de son code, Voici une version légèrement ajustée:

SUBSTRING(
  sentence,
  LOCATE(' ', sentence) + CHAR_LENGTH(' '),
  LOCATE(' ', sentence,
  ( LOCATE(' ', sentence) + 1 ) - ( LOCATE(' ', sentence) + CHAR_LENGTH(' ') )
)

comme exemple de travail, j'ai utilisé:

SELECT SUBSTRING(
  sentence,
  LOCATE(' ', sentence) + CHAR_LENGTH(' '),
  LOCATE(' ', sentence,
  ( LOCATE(' ', sentence) + 1 ) - ( LOCATE(' ', sentence) + CHAR_LENGTH(' ') )
) as string
FROM (SELECT 'THIS IS A TEST' AS sentence) temp

ceci extrait avec succès le mot IS

44
répondu Brendan Bullen 2017-08-03 13:33:30

option plus courte pour extraire le second mot dans une phrase:

SELECT SUBSTRING_INDEX(SUBSTRING_INDEX('THIS IS A TEST', ' ',  2), ' ', -1) as FoundText

MySQL docs for SUBSTRING_INDEX

27
répondu Damien Goor 2016-03-23 18:44:54

selon http://dev.mysql.com / la fonction de substrat utilise la position de départ puis la longueur donc sûrement la fonction pour le second mot serait:

SUBSTRING(sentence,LOCATE(' ',sentence),(LOCATE(' ',LOCATE(' ',sentence))-LOCATE(' ',sentence)))
14
répondu BenWells 2016-08-11 06:26:58

Non, il n'y a pas de syntaxe pour extraire du texte en utilisant des expressions régulières. Vous devez utiliser l'ordinaire les fonctions de manipulation de chaîne .

sélectionnez alternativement la valeur entière de la base de données (ou les premiers N caractères si vous craignez trop de transfert de données) et utilisez ensuite une expression régulière sur le client.

7
répondu Mark Byers 2010-10-26 07:30:34

comme d'autres l'ont dit, mysql ne fournit pas d'outils regex pour extraire les sous-chaînes. Cela ne veut pas dire que vous ne pouvez pas les avoir si vous êtes prêt à étendre mysql avec des fonctions définies par l'utilisateur:

https://github.com/mysqludf/lib_mysqludf_preg

qui peut ne pas être beaucoup d'aide si vous voulez distribuer votre logiciel, étant un obstacle à l'installation de votre logiciel, mais pour une solution interne, il peut être approprié.

5
répondu mc0e 2013-08-19 06:00:22

j'ai utilisé la réponse de Brendan Bullen comme point de départ pour un problème similaire que j'ai eu qui était de retrouver la valeur d'un champ spécifique dans une chaîne JSON. Toutefois, comme j'ai commenté sa réponse, elle n'est pas tout à fait exacte. Si votre limite gauche n'est pas juste un espace comme dans la question originale, alors l'écart augmente.

solution corrigée:

SUBSTRING(
    sentence,
    LOCATE(' ', sentence) + 1,
    LOCATE(' ', sentence, (LOCATE(' ', sentence) + 1)) - LOCATE(' ', sentence) - 1
)

les deux différences sont le +1 dans le paramètre de L'indice de substrat et le -1 dans les paramètres de longueur.

Pour une solution générale à "trouver la première occurrence d'une chaîne entre deux limites":

SUBSTRING(
    haystack,
    LOCATE('<leftBoundary>', haystack) + CHAR_LENGTH('<leftBoundary>'),
    LOCATE(
        '<rightBoundary>',
        haystack,
        LOCATE('<leftBoundary>', haystack) + CHAR_LENGTH('<leftBoundary>')
    )
    - (LOCATE('<leftBoundary>', haystack) + CHAR_LENGTH('<leftBoundary>'))
)
5
répondu Hypolite Petovan 2016-08-26 20:05:57

Je ne pense pas qu'une telle chose soit possible. Vous pouvez utiliser la fonction de soustring pour extraire la partie que vous voulez.

2
répondu user483085 2010-10-26 07:30:28

Mon home-grown expression régulière remplacer la fonction peut être utilisé pour cela.

Démo

Voir ce DB-Violon démo , qui renvoie le deuxième mot ("je") à partir d'un célèbre sonnet et le nombre d'occurrences de celui-ci (1).

SQL

en supposant que MySQL 8 ou plus est utilisé (pour permettre l'utilisation d'un (Common Table Expression ), le deuxième mot et le nombre d'occurrences de celui-ci seront retournés par la suite:

WITH cte AS (
     SELECT digits.idx,
            SUBSTRING_INDEX(SUBSTRING_INDEX(words, '~', digits.idx + 1), '~', -1) word
     FROM
     (SELECT reg_replace(UPPER(txt),
                         '[^''’a-zA-Z-]+',
                         '~',
                         TRUE,
                         1,
                         0) AS words
      FROM tbl) delimited
     INNER JOIN
     (SELECT @row := @row + 1 as idx FROM 
      (SELECT 0 UNION ALL SELECT 1 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) t1,
      (SELECT 0 UNION ALL SELECT 1 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) t2, 
      (SELECT 0 UNION ALL SELECT 1 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) t3, 
      (SELECT 0 UNION ALL SELECT 1 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) t4, 
      (SELECT @row := -1) t5) digits
     ON LENGTH(REPLACE(words, '~' , '')) <= LENGTH(words) - digits.idx)
SELECT c.word,
       subq.occurrences
FROM cte c
LEFT JOIN (
  SELECT word,
         COUNT(*) AS occurrences
  FROM cte
  GROUP BY word
) subq
ON c.word = subq.word
WHERE idx = 1; /* idx is zero-based so 1 here gets the second word */

explication

quelques trucs sont utilisés dans le SQL ci-dessus et une certaine accréditation est nécessaire. Tout d'abord, l'expression régulière "remplacer" est utilisée pour remplacer tous les blocs continus de caractères non verbaux-chaque bloc étant remplacé par un seul caractère tilda ( ~ ). Note: un caractère différent pourrait être choisi s'il y a une possibilité qu'un tilda apparaisse dans le texte.

la technique de cette réponse est alors utilisée pour transformer une chaîne avec des valeurs délimitées en valeurs de ligne séparées. Il est combiné avec la technique intelligente de cette réponse pour produire une table composée d'une séquence d'incrémentation des nombres: 0 - 10.000 dans ce cas.

0
répondu Steve Chambers 2018-05-21 10:08:23

la valeur du champ est:

 "- DE-HEB 20% - DTopTen 1.2%"
SELECT ....
SUBSTRING_INDEX(SUBSTRING_INDEX(DesctosAplicados, 'DE-HEB ',  -1), '-', 1) DE-HEB ,
SUBSTRING_INDEX(SUBSTRING_INDEX(DesctosAplicados, 'DTopTen ',  -1), '-', 1) DTopTen ,

FROM TABLA 

résultat:

  DE-HEB       DTopTEn
    20%          1.2%
-3
répondu Antonio Rivera 2012-11-01 00:07:02