jueves, 4 de julio de 2013

Opciones de actualización con LIKE REGEXP SUBSTRING y localizar

Original post: http://anothermysqldba.blogspot.com/2013/07/update-options-with-like-regexp.html

Un post reciente foro me hizo parar y pensar por un momento .. 
http://forums.mysql.com/read.php?10, 589573,589573 # msg-589573 

El problema era que el usuario desea actualizar sólo la palabra audi y no la palabra auditor. 
Se resolvió mediante el aprovechamiento del período con facilidad una vez que dejé de tratar de usar SUBSTRING y localizar. Ellos querían una solución rápida y fácil, después de todo. 


root@localhost [test]> CREATE TABLE `forumpost` (
-> `name` varchar(255) DEFAULT NULL
-> ) ENGINE=InnoDB;

root@localhost [test]> insert into forumpost value ('An auditor drives an audi.'),('An auditor drives a volvo.');

root@localhost [test]> select * from forumpost;
+----------------------------+
| name |
+----------------------------+
| An auditor drives an audi. |
| An auditor drives a volvo. |
+----------------------------+ 


Así que ahora vamos a actualizar la manera fácil y rápida, aprovechando el período 

root@localhost [test]>UPDATE forumpost SET name = REPLACE(name, 'audi.', 'toyota.') WHERE name LIKE '%audi.';
Query OK, 1 row affected (0.20 sec)
Rows matched: 1 Changed: 1 Warnings: 0

root@localhost [test]> select * from forumpost;
+------------------------------+
| name |
+------------------------------+
| An auditor drives an toyota. |
| An auditor drives a volvo. |
+------------------------------+ 


Pero ... ¿qué pasa con las opciones válidas de SUBSTRING y localizar ..... 


root@localhost [test]> insert into forumpost value ('An auditor drives an audi.');
root@localhost [test]> insert into forumpost value ('An auditor drives an audi car');
root@localhost [test]> select * from forumpost;
+-------------------------------+
| name |
+-------------------------------+
| An auditor drives an toyota. |
| An auditor drives a volvo. |
| An auditor drives an audi. |
| An auditor drives an audi car |
+-------------------------------+ 


Primera prueba sus opciones por lo que asegúrese de que usted puede encontrar lo que buscas .. 


root@localhost [test]> SELECT * FROM forumpost WHERE name REGEXP 'audi car$';
+-------------------------------+
| name |
+-------------------------------+
| An auditor drives an audi car |
+-------------------------------+ 

root@localhost [test]> SELECT * FROM forumpost WHERE name LIKE '%audi car%';
+-------------------------------+
| name |
+-------------------------------+
| An auditor drives an audi car |
+-------------------------------+


Eso realmente no hizo mucho, ya que acaba de cambiar el período de la palabra coche. Así que sigue adelante .... 

Tenemos que sacar sólo la palabra audi de la línea con el coche audi. 

root@localhost [test]> SELECT SUBSTRING(name,-8,4), name FROM forumpost WHERE SUBSTRING(name,-8,4) = 'audi';
+----------------------+-------------------------------+
| SUBSTRING(name,-8,4) | name |
+----------------------+-------------------------------+
| audi | An auditor drives an audi car |
+----------------------+-------------------------------+ 


El SUBSTRING me permitió tirar de los 4 primeros caracteres después conté de nuevo 8 caracteres del final. 

¿Y qué si usted no sabe la ubicación de los personajes? 
Para empezar se debe revisar sus datos para asegurarse de que usted sabe lo que está después. Sin embargo, los personajes pueden moverse por la cadena por lo que permite trabajar con LOCATE. 

Voy a añadir otra fila sólo para pruebas. 

root@localhost [test]> insert into forumpost value ('An auditor drives an red audi car');
Query OK, 1 row affected (0.04 sec)

root@localhost [test]> select * from forumpost;
+------------------------------------+
| name |
+------------------------------------+
| An auditor drives an toyota. |
| An auditor drives a volvo. |
| An auditor drives an audi. |
| An auditor drives an audi car |
| An auditor drives an audi blue car |
| An auditor drives an red audi car |
+------------------------------------+ 


Así que, independientemente de la conclusión, podemos ver que audi siempre después de auditor, así que sólo hay que pasar por alto esa palabra. La palabra auditor está en los primeros 8 caracteres para omitir esos. 

root@localhost [test]> SELECT LOCATE('audi', name,8), name FROM forumpost WHERE LOCATE('audi', name,8) > 0 ;
+------------------------+------------------------------------+
| LOCATE('audi', name,8) | name |
+------------------------+------------------------------------+
| 22 | An auditor drives an audi. |
| 22 | An auditor drives an audi car |
| 22 | An auditor drives an audi blue car |
| 26 | An auditor drives an red audi car |
+------------------------+------------------------------------+ 


Aceptar así que encontramos los que buscamos. Ahora tenemos que escribir la instrucción de actualización. 

No podemos usar la sustituya este momento. 

UPDATE forumpost SET name = REPLACE(name, LOCATE('audi', name,8), 'mercedes') WHERE LOCATE('audi', name,8) > 0 ;
Query OK, 0 rows affected (0.02 sec)
Rows matched: 4 Changed: 0 Warnings: 0 

Note que encontró las filas, pero no cambió nada. 

Así que intentarlo de nuevo y yo no quiero asumir la posición 8. Quiero que el segundo valor de audi. 
Así que una prueba muestra que con SUBSTRING_INDEX puedo saltar el primero uno y Uso CONCAT 

SELECT name , CONCAT ( SUBSTRING_INDEX(name, 'audi', 2) , ' mercedes ' , SUBSTRING_INDEX(name, 'audi', -1) ) as newvalue
FROM forumpost
WHERE LOCATE('audi', name,10) > 0 ;
+-----------------------------------+-----------------------------------------+
| name | newvalue |
+-----------------------------------+-----------------------------------------+
| An auditor drives an audi. | An auditor drives an mercedes . |
| An auditor drives an audi. | An auditor drives an mercedes . |
| An auditor drives an audi car | An auditor drives an mercedes car |
| An auditor drives an red audi car | An auditor drives an red mercedes car |
+-----------------------------------+-----------------------------------------+

root@localhost [test]> UPDATE forumpost SET name = CONCAT(SUBSTRING_INDEX(name, 'audi', 2) , ' mercedes ' , SUBSTRING_INDEX(name, 'audi', -1) )
WHERE LOCATE('audi', name,10) > 0 ;
Query OK, 4 rows affected (0.03 sec)
Rows matched: 4 Changed: 4 Warnings: 0

root@localhost [test]> select * from forumpost;
+-----------------------------------------+
| name |
+-----------------------------------------+
| An auditor drives an mercedes . |
| An auditor drives a volvo. |
| An auditor drives an mercedes . |
| An auditor drives an mercedes car |
| An auditor drives an red mercedes car |
+-----------------------------------------+
5 rows in set (0.00 sec) 


Ahora, otorgó a la gramática con el uso de "uno" no es válido, pero esa es otra historia. 

Más información al respecto se puede encontrar aquí: