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 :)
5 comentarios:
¡Me acabas de regalar por lo menos una hora! Exactamente lo que buscaba.Muchas gracias.
hola, la verdad necesito lo mismo que uds, pero desde visual 2010 o 2012.
necesito saber si el estado de un cliente es = false o 0 y saber, desde otra tabla, si la fecha que esta inserta en igual o menor a la actual. esto para el vencimiento de cuotas y el estado es para bloquear al cliente si no pago.
seria de mucha ayuda si alguien me puede apoyar.
Gracias!!!
Y @expediente la ocupaste para?
Muchas pero muchas gracias... me habia dado vueltas y vueltas para encontrar la manera de como actualizar las lineas de la tabla que su valor cambiaba por la salida de producto... era simple..mi linea decia que tenia 5 unidades..y la misma linea decia que tenia 3 comprometidos para vender.. osea que en la siguiente linea donde apareciera el produto no podia comparar con los antiguos 5 del stock .. si no que con la resta del stock menos lo comprometido (que eran 3).. por lo que mi nuevo stock eran 2 para la linea siguiente. Asi que MUCHAS GRACIAS ...
si a alguien le sirve.. dejo mi codigo.. saludos a todos:
declare @codigo_art as nvarchar(16)
declare @numnota as int
declare @item_notde as int
declare @veces as int
declare @cantidad_pend as numeric(38, 2)
declare @Total_STKyOC as numeric(38, 2)
declare @codigo_art_ANTERIOR as nvarchar(16)
declare @cantidad_pend_ANTERIOR as numeric(38, 2)
declare @Total_STKyOC_ANTERIOR as numeric(38, 2)
declare CURSORNV cursor for
select codigo_art,numnota,item_notde,veces, cantidad_pend, Total_STKyOC from T_Web_CheckNV_2015
Where veces > 1
Order by codigo_art,numnota,item_notde
SET @Total_STKyOC_ANTERIOR = (select top 1 Total_STKyOC from T_Web_CheckNV_2015 where veces > 1)
SET @cantidad_pend_ANTERIOR = 0
SET @codigo_art_ANTERIOR = (select top 1 codigo_art from T_Web_CheckNV_2015 where veces > 1)
open CURSORNV
fetch next from CURSORNV into @codigo_art, @numnota,@item_notde,@veces,@cantidad_pend,@Total_STKyOC
while @@fetch_status = 0
begin
update T_Web_CheckNV_2015 set Total_STKyOC = @Total_STKyOC - @cantidad_pend_ANTERIOR
where codigo_art=@codigo_art and numnota = @numnota and item_notde=@item_notde
SET @codigo_art_ANTERIOR = @codigo_art
SET @cantidad_pend_ANTERIOR = @cantidad_pend_ANTERIOR + @cantidad_pend
fetch next from CURSORNV into @codigo_art, @numnota,@item_notde,@veces,@cantidad_pend,@Total_STKyOC
IF @codigo_art <> @codigo_art_ANTERIOR
BEGIN
SET @cantidad_pend_ANTERIOR = 0
update T_Web_CheckNV_2015 set Total_STKyOC = @Total_STKyOC - @cantidad_pend_ANTERIOR
where codigo_art=@codigo_art and numnota = @numnota and item_notde=@item_notde
SET @codigo_art_ANTERIOR = @codigo_art
SET @cantidad_pend_ANTERIOR = @cantidad_pend_ANTERIOR + @cantidad_pend
fetch next from CURSORNV into @codigo_art, @numnota,@item_notde,@veces,@cantidad_pend,@Total_STKyOC
END
end
close CURSORNV
deallocate CURSORNV
Estimado, gracias por dejar el codigo fuente. me soluciono un problema super grande!
saludos.
Publicar un comentario