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?
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
option plus courte pour extraire le second mot dans une phrase:
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX('THIS IS A TEST', ' ', 2), ' ', -1) as FoundText
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)))
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.
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é.
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>'))
)
Je ne pense pas qu'une telle chose soit possible. Vous pouvez utiliser la fonction de soustring pour extraire la partie que vous voulez.
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.
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%