miércoles, 21 de febrero de 2018

A vueltas con UPDATE

Más pronto o más tarde nos encontraremos con esta situación. Aprovecho la base de datos EJEMPLO y su tabla PROFESORES de la asignatura —y de paso enlazo FBDdocs—. Si quieres seguir la historia que voy a contar, nada más fácil que usar tu base de datos propia y hacer

create table profesores (select * from ejemplo.profesores)

Ahora tienes una copia de esa tabla y puedes modificar sus filas.


El caso que quiero plantear es típico, te pasan una lista de modificaciones que debes incorporar a tu base de datos. En esta ocasión, actualizaciones de la categoría de cada profesor. Te puede venir en un archivo CSV, en texto tabulado, yo qué se... A nosotros nos han mandado esto que ya tenemos en una tabla auxiliar PROF2.



El ejemplo solo tiene 3 filas pero estamos hablando de cuando hay 1000, 2000, 100000 filas que actualizar. No te vas a poner a

update profesores set categoría='TU' where dni='21111222'

Y así hasta terminar con los 1000, 2000... Ni hablar, lo que yo quiero es una única instrucción que los actualice todos de golpe. El problema es que update solo trabaja con una fila y unicamente conoce los valores de la fila que filtremos. Debo conseguir que update disponga de toda la información correlacionada para cada fila de PROFESOR.

Llegará el típico programador que solo piensa en bucles e iteraciones y dirá !cursores!. Que no, que SQL no es iterativo, ni falta que le hace. Para eso está el JOIN. ¿Verdad que si concateno las filas dispongo de toda la información necesaria?

select * from profesores p join prof2 p2 on (p.dni=p2.dni)


Si la tabla se llamara RESULTADO sería tan simple como

update RESULTADO set categoria = nueva

En cada fila, reemplazaría el valor de "categoría" por el de "nueva". Fenómeno, pero no es lo que queremos, la tabla PROFESORES no es la tabla RESULTADO. Pero casi, vamos a aprovechar el JOIN:

update 
profesores p join prof2 p2 on (p.dni=p2.dni)
set p.categoria=p2.categoria

Y a continuación select * from profesores:


Parece magia pero no lo es. El servidor sabe en todo momento qué columnas está manejando —las de profesores y las de prof2— y simplemente usa un resultado intermedio —el join— para disponer de todos los datos necesarios antes de actualizar los valores de una columna. Finalmente, como la columna PROFESORES.categoria es la que se actualiza, es la tabla PROFESORES la que recibe dicha modificación. Fijate que si hubiéramos hecho set p2.categoria=p.categoria, o sea, al revés, habría sido PROF2 la tabla actualizada.

Dice MySQL que soporta UPDATE multitabla, esto es, lo de antes o bien su equivalente:

update profesores p, prof2 p2
set p.categoria=p2.categoria
where p.dni=p2.dni

Ya depende de con qué estés más cómodo. Lo cierto es que la sintaxis JOIN permite el uso de LEFT JOIN en un UPDATE, cosa que no podrías hacer con justo lo anterior. Asegúrate, eso sí, de que tu servidor de base de datos admite la una y la otra y en qué condiciones. Por lo general, el UPDATE-JOIN funciona.

Amantes de los bucles, no lloréis.