jueves 16 de septiembre de 2010

SQL. Recorrer y actualizar ciertos registros de una tabla. Cursores.

A veces, mi ignorancia en el lenguaje SQL que hace verme forzado a trabajar en horas intempestivas como hoy (terminar a las 02:00 para reiniciar a las 06:00).

El problema es que tengo una tabla de cientos de miles de registros con un campo expediente que tiene que ser único. Es decir, que no admita duplicados. Y en dicho campo, 290 mil registros tienen un valor que es vacio, es cero o es directamente null.

El quid del asunto es localizar dichos registros y actualizarme el campo expediente con una id construido.

Después de demasiadas horas perdidas, la madrugada y un reparador mini sueño, me trajo la respuesta en forma de Cursores.

Primero declaremos las variables que voy a utilizar en las operaciones.

-- Id del registro
-- Campo expediente a modificar
-- Contador, campo numérico autoincremental que vamos a almacenar en el campo expediente
declare @id as nvarchar(16)
declare @expediente as varchar(30)
declare @contador as int

A continuación declaramos el cursor, para manipular los datos solamente sobre los expedientes que cumplen la condición, en vez de sobre los cientos de miles de toda la tabla.

declare CURSORVC cursor for
  select id, expediente  from Tabla
  Where
  expediente = '0'
  OR expediente = ''
  OR expediente = null
  OR expediente IS NULL
  Order by id

Inicializamos el contador.

SET @contador = 10

Y abrimos el cursor, recuperando la primera fila. Aquí lo único que hay que tener cuidado es que las variables en las que cargamos los datos del cursor sean correspondientes a los campos obtenidos en la select de la declaración del cursor.

open CURSORVC
  fetch next from CURSORVC into @id, @expediente

A continuación iniciamos el bucle

while @@fetch_status = 0
    begin

Actualizamos los datos del campo expediente cuando el id sea el del registro que nos ha traido el cursor

update Tabla set expediente =  CAST(@contador As varchar(10)) + ' -2010'
    where id=@id
    -- Avanzamos otro registro
    fetch next from CURSORVC into @id, @expediente

-- Avanzamos el contador en uno
    set @contador = @contador + 1
   end

Y fínalmente cerramos el cursor y lo eliminamos de memoria

      close CURSORVC
deallocate CURSORVC

Y así, lo que por código tardaba horrores, pero horrores de los malos, ahora he actualizado los casi trescientos mil registros en menos de tres minutos.

P.D. Besitos al Borjus que me recordó que con experiencia un cursor como este se hace en unos 10 minutos, contra las cinco horas que me ha costado el primero mío :)