2010-04-30 8 views
8

Je souhaite extraire un mot d'une colonne de chaîne d'une table.Quel est l'équivalent de REGEXP_SUBSTR dans mysql?

description 
=========================== 
abc order_id: 2 xxxx yyy aa 
mmm order_id: 3 nn kk yw 

Résultat attendu mis

order_id 
=========================== 
2 
3 

Table sera au plus ont 100 lignes, la longueur du texte est ~ 256 omble chevalier et la colonne a toujours un order_id présent. Donc, la performance n'est pas un problème.

Dans Oracle, je peux utiliser REGEXP_SUBSTR pour ce problème. Comment pourrais-je résoudre cela dans MySQL?

Modifier 1

J'utilise LOCATE et SUBSTR pour résoudre le problème. Le code est moche. Dix minutes après avoir écrit le code, je maudis le gars qui a écrit un code si moche.

Je n'ai pas trouvé la fonction REGEXP_SUBSTR dans les documents MySQL. Mais j'espère qu'il existe ..

Réponse à: Pourquoi la table ne peut-elle être optimisée? Pourquoi les données sont-elles stockées de manière si bête?

L'exemple que j'ai donné indique simplement le problème que j'essaie de résoudre. Dans un scénario réel, j'utilise un logiciel de mise en file d'attente de tierce partie basé sur DB pour exécuter des tâches asynchrones. La file d'attente sérialise l'objet Ruby en tant que texte. Je n'ai aucun contrôle sur la structure de la table OU le format de données. Les tâches dans la file d'attente peuvent être récurrentes. Dans notre configuration de test, certaines tâches récurrentes échouent à cause de données périmées. Je dois supprimer ces tâches pour éviter l'erreur. De telles erreurs ne sont pas communes, par conséquent je ne veux pas maintenir une table d'ombre normalisée.

Répondre

3

Comme l'a dit Konerak, il n'y a pas d'équivalent de REGEXP_SUBSTR dans MySQL. Vous pouvez faire ce que vous avez besoin en utilisant la logique de SUBSTRING, mais il est laid:

SELECT 
    SUBSTRING(lastPart.end, 1, LOCATE(' ', lastPart.end) - 1) AS orderId 
FROM 
    (
    SELECT 
     SUBSTRING(dataset.description, LOCATE('order_id: ', dataset.description) + LENGTH('order_id: ')) AS end 
    FROM 
     (
     SELECT 'abc order_id: 2 xxxx yyy aa' AS description 
     UNION SELECT 'mmm order_id: 3 nn kk yw' AS description 
     UNION SELECT 'mmm order_id: 1523 nn kk yw' AS description 
    ) AS dataset 
    ) AS lastPart 

Edit: Vous pouvez essayer ce user defined function l'accès à l'expression rationnelle Perl dans MySql

SELECT 
    PREG_CAPTURE('/.*order_id:\s(\d+).*/', dataset.description,1) 
FROM 
    (
    SELECT 'abc order_id: 2 xxxx yyy aa' AS description 
    UNION SELECT 'mmm order_id: 3 nn kk yw' AS description 
    UNION SELECT 'mmm order_id: 1523 nn kk yw' AS description 
) AS dataset 
+1

C'est ce que je fais. +1 pour avoir pris le temps d'écrire ceci .. –

+1

La réponse éditée pour utiliser CHAR_LENGTH() au lieu de LENGTH(), ce dernier renvoie la taille occupée en octets, et non la longueur de la chaîne. Vous aurez des problèmes avec UTF8 par exemple –

1

Il n'y a pas d'équivalent MySQL. Le REGEXP de MySQL peut être utilisé pour les chaînes correspondantes, mais pas pour les transformer.

Vous pouvez soit essayer de travailler avec des procédures stockées et beaucoup de logique REPLACE/SUBSTRING, ou le faire dans votre langage de programmation - ce qui devrait être l'option la plus facile. Mais êtes-vous sûr que votre format de données est bien choisi? Si vous avez besoin de l'order_id, cela n'aurait-il pas de sens de le stocker dans une colonne différente, de sorte que vous pouvez mettre des index, utiliser des jointures et des likes?

+1

Nous ne pouvons pas toujours choisir notre format de données. Par exemple, lors de la migration de données ou de l'importation de données à partir d'un autre système, nous devons fréquemment gérer tout ce qui nous est donné. – APC

+0

Lisez ma question mise à jour pour la raison pour laquelle j'ai une telle donnée. –

0

ou vous peut le faire et vous épargner la laideur:

select SUBSTRING_INDEX(SUBSTRING_INDEX('habc order_id: 2 xxxx yyy aa',' ',3),' ',-1);