TRIGGER DELETE

23/06/2004 - 11:06 por Celeste | Informe spam
Hola, tengo un trigger de delete que comprueba que para poder borrrar el
registro cumple unas condiciones (que no sea el ultimo con un código
determinado, que no este dado de baja...), es decir muchas comprobaciones,
si yo hago un delete from tabla1 where cod =1 ; me hace las comprobaciones,
es decir, salta el trigger.
El problema es si hago un delete from tabla1.

no salta el trigger y los elimina todos.

¿porque ocurre esto?
¿que debo hacer?
¿deberia usar un cursor??


gracias.

Preguntas similare

Leer las respuestas

#16 Salvador Ramos
23/06/2004 - 17:51 | Informe spam
Se ejecuta una vez. Lo que si que puedes es utilizar la tabla deleted en el
trigger donde tendrás información de todas las filas borradas.

Puedes ver ejemplos de triggers en www.portalsql.com, igual te aclaran sobre
su uso, y por supuesto en la propia ayuda.

Un saludo
Salvador Ramos
Murcia - España
[MVP SQL Server]
www.helpdna.net

"Celeste" escribió en el mensaje
news:
No funciona, esta comprobado que se borran todos.

mi duda es:

Si yo quiero borrar 1000 registros ¿cuantas veces se activa el trigger
de delete?

1000 o 1.

gracias.


Respuesta Responder a este mensaje
#17 ulises
23/06/2004 - 18:11 | Informe spam
Con permiso de Carlos y Liliana, primero hay que aclarar
que el trigger en Ms SQL Server solo se invoca una vez por
cada sentencia que se realiza, es decir si realizas un
DELETE el trigger SOLO se ejecutará una vez se hayan
borrado 1 ó 1000 registros, es por eso importante que la
implementación del trigger contemple el manejo de un
conjunto de resultados y no se considere solo un registro,
el problema que se presentaría en tu caso es que si
encuentras un error en la eliminación y haces un ROLLBACK
estarías revertiendo TODAS las eliminaciones realizadas y
no solamente la que no deseas, si esto no es un problema
podrías hacer algo como (sin probar):

crete trigger td_movimiento on dbo.movimientos
for delete as
begin
/* verifica que no se haya eliminado algun producto que ya
se haya dado de baja */
if exists ( select obj_fechabaja from objetos
where obj_codigo
in ( select obj_codigo from deleted ) )
ROLLBACK transaction

/* verifica que no existan movimientos posteriores a los
eliminados en los productos */
if exists ( select obj_codigo, mov_mto
from movimientos m
where mov_mto > ( select max(mov_mto)
from deleted
where obj_codigo m.obj_codigo )
group by obj_codigo )
ROLLBACK transaction

/* Actualiza ubicaciones (no he entendido bien esto) */
update ubicaciones
set u.obj_codigo = null
from ubicaciones u join deleted d
on u.obj_codigo = d.obj_codigo

update ubicaciones
set u.obj_codigo = d.obj_codigo
from ubicaciones u join deleted d
on u.ubi_id = d.mov_ubiorigen

end

Saludos,
Ulises

Lo que yo quiero hacer es:

crete trigger td_movimiento on dbo.movimientos for


delete as
begin
declare @new_mov_mto int
declare @new_obj_codigo char(10)
declare @new_mov_fecha datetime
declare @new_mov_ubiorigen int
declare @new_mov_ubidestino int
declare @new_mov_documento char(10)
declare @new_mov_descripcion char(10)


declare @old_mov_mto int
declare @old_obj_codigo char(10)
declare @old_mov_fecha datetime
declare @old_mov_ubiorigen int
declare @old_mov_ubidestino int
declare @old_mov_documento char(10)
declare @old_mov_descripcion char(10)

declare @errno int
declare @errmsg char(255)
declare @numrows int

declare @v_ubi_id int
declare @v_obj_codigo char(10)
declare @v_ubi_fecha datetime
declare @v_mov_fecha datetime
declare @v_mov_ubidestino int
declare @v_mov_mto int
declare @variable char(10)
declare @flag_valor int


select
@new_mov_mto = inserted.mov_mto,
@new_obj_codigo = inserted.obj_codigo,
@new_mov_fecha = inserted.mov_fecha,
@new_mov_ubiorigen = inserted.mov_ubiorigen,
@new_mov_ubidestino = inserted.mov_ubidestino,
@new_mov_documento = inserted.mov_documento,
@new_mov_ubidestino = inserted.mov_ubidestino,
@new_mov_descripcion = inserted.mov_descripcion
from inserted

select
@old_mov_mto = deleted.mov_mto,
@old_obj_codigo = deleted.obj_codigo,
@old_mov_fecha = deleted.mov_fecha,
@old_mov_ubiorigen = deleted.mov_ubiorigen,
@old_mov_ubidestino = deleted.mov_ubidestino,
@old_mov_documento = deleted.mov_documento,
@old_mov_ubidestino = deleted.mov_ubidestino,
@old_mov_descripcion = deleted.mov_descripcion
from deleted



select @v_ubi_fecha = obj_fecbaja
from Objetos
where obj_codigo=@old_obj_codigo


if @v_ubi_fecha is not null BEGIN
set @errno = -1002
set @errmsg = 'Este objeto esta dado de baja, no


se puede modificar
ni eliminar.'
RAISERROR ( @errmsg,16,1)
goto on_error
END
select @v_mov_mto=max (MOV_MTO)
from MOVIMIENTOS
WHERE obj_codigo = @old_obj_codigo
group by obj_codigo

if @old_mov_mto < @v_mov_mto begin
set @errno = -1002
set @errmsg = 'No se pueden eliminar el movimiento, hay


movimientos
posteriores.'
RAISERROR ( @errmsg,16,1)
goto on_error
end

else begin


antes.

update UBICACIONES
set obj_codigo=null
where obj_codigo=@old_obj_codigo


update UBICACIONES
set obj_codigo=@old_obj_codigo
where ubi_id=@old_mov_ubiorigen

end
end

end
EXECUTE p_identitymov @OLD_mov_mto



GoTo fim
on_error:
if @@error <> 0 begin
rollback transaction
end
fim:


-

-

Es decir, cuando yo elimino un movimiento, este actualiza


la tabla
ubicaciones ESTO FUNCIONA PERFECTAMENTE.

El problema es si desde el analizador de consutlas hago:

delete from movimiento


ya que sólo salta el trigger en el último registro y si


este se puede
eliminar se me eliminan todos los registros, si no se


puede eliminar ya que
esta el objeto dado de baja o no es el ultimo me genera


el mensaje de error
y se cancela todo.

De todas formas, si se hiciera bien el delete me


actualizaría la tabla
ubicaciones, pero no lo hace.

Lo que necesito que que si yo escribo : "delete from


movimiento " y tengo
1938 registros, que el trigger salte 1938 veces y me


actualice la tabla
ubicaciones cada vez y si el número 52 que va a eliminar


esta dado de baja
lo cancele todo.

Por lo que veo la única forma es utilizando cursores ya


que no encuentro
otra manera o ¿si que la hay?????



Gracias.


























.

Respuesta Responder a este mensaje
#18 Celeste
23/06/2004 - 18:42 | Informe spam
GRACIAS ESO ES LO QUE NECESITABA.

Gracias por aclarme que el trigger se lanza 1 vez en cada sentencia.

Pero esto no me vale ya que lo que yo tengo son dos tablas ubicacioens y
movimetos que tienen que estar actualizadas entre ellas, si yo elimino 2
registros tengo que entrar dos veces en el trigger y realizar lo que esta
escribo dentro PERO DOS VECES.

Por lo tanto la comprobacion de si he dado de baja si que me vale, pero lo
de controlar ubicaciones-movimietnos no me vale, asi que creo que con lo que
me has contado (que se lanza 1 vez en cada sentencia) voy a realizar un
cursor (si no me comentas nada mas).

Pero eso será mañana que lo probaré todo.


Saudos.
Respuesta Responder a este mensaje
#19 Javier Loria
23/06/2004 - 19:00 | Informe spam
Hola Celeste:
Si me permiten Carlos y Lilliana.
SQL es acerca de CONJUNTOS DE DATOS, el codigo del Trigger que enviaste
no usa un conjunto de Datos y por ende cuando se hace el DELETE de varias
filas falla. El Trigger NO FUNCIONA bajo conjuntos de Datos. Algunos motores
de bases de datos construyen internamente cursores para permitir correr los
triggers tantas veces como filas se esten borrando. El FOR EACH ROW es
precismente un cursor disfrazado. MS SQL NO TIENE esta sintaxis.
Tienes 2 alternativas:
a) Crear un cursor y borrarlo fila por fila, en cuyo caso te recomiendo
cambies el codigo del trigger para hacer un SELECT COUNT(*) FROM Deleted y
si da mas de 1 genere un error para evitar que los programadores que si
saben usar conjuntos de datos tengan problemas. Esto te permite hacer lo que
deseas con con poco ezfuerzo.
b) Cambiar el codigo para que use CONJUNTOS DE DATOS. Esto no es
sencillo y requiere un cambio de mentalidad sobre todo si tienes experiencia
en programacion. La ventaja de este metodo es que podras hacer codigo
cientos o miles de veces mas rapido que el anterior y mucho mas compatible
con otras plataformas.
El siguiente codigo esta sin probar, asi que puede tener errores de
sintaxis, pero te lo envio por si te sirva de guia. Adicionalmente el
Trigger es solo de Delete asi que no tiene INSERTED:
La primera condicion en SQL puede ser expresada como:
IF EXISTS (SELECT *
FROM Deleted
JOIN Objetos
ON Deleted.obj_codigo=Objetos.obj_codigo
WHERE obj_fecbaja IS NULL)
BEGIN
ROLLBACK
RAISERROR ('Este objeto esta dado de baja, no se puede modificar ni
eliminar.' ,16,1)
RETURN
END
Este codigo es mucho mas simple que el que escribiste, miles de veces
mas rapido porque usa los datos como CONJUNTOS y no como registros.
La segunda condicion
IF EXISTS( SELECT *
FROM Movimientos
JOIN Deleted
ON Movimientos.obj_codigo=deleted.obj_codigo
WHERE Movimientos.mov_mto>Deleted.Mov_Mto)
BEGIN
ROLLBACK
RAISERROR ('No se pueden eliminar el movimiento, hay movimientos
posteriores.',16,1)
RETURN
END
Del UPDATE no estoy seguro de entenderlo bien pero creo que puede escribirse
como:
UPDATE Ubicaciones
SET obj_codigo=NULL
FROM Ubicaciones
JOIN Deleted
ON Ubicaciones.obj_codigo=Deleted.obj_codigo

UPDATE Ubicaciones
SET obj_codigo=Deleted.mov_ubiorigen
FROM Ubicaciones
JOIN Deleted
ON Ubicaciones.ubi_id=Deleted.mov_ubiorigen
Podrian existir algunos problemas al actualizarce multiples filas del
mismo mov_ubiorigen, y abria que revisar el criterio de seleccion de la
ubicacion. Una nota adicional esta sintaxis no es STANDARD ANSI por lo que
es posible que tenga problemas en otros motores o en otras versiones de SQL.
Si escribir ANSI es imporante puede reexpresarse como:
UPDATE .. SET ... WHERE Columna IN (SELECT ...FROM ... WHERE ... )
Por ultimo habria que saber que hace el procedimiento P_IdentityMov para
resolver el problema con conjuntos y con filas.
Saludos,


Javier Loria
Costa Rica
Se aprecia la inclusion de DDL (CREATE, INSERTS, etc.)
que pueda ser copiado y pegado al Query Analizer.
La version de SQL y Service Pack tambien ayuda.


Celeste escribio:
Lo que yo quiero hacer es:

crete trigger td_movimiento on dbo.movimientos for delete as
begin
declare @new_mov_mto int
declare @new_obj_codigo char(10)
declare @new_mov_fecha datetime
declare @new_mov_ubiorigen int
declare @new_mov_ubidestino int
declare @new_mov_documento char(10)
declare @new_mov_descripcion char(10)


declare @old_mov_mto int
declare @old_obj_codigo char(10)
declare @old_mov_fecha datetime
declare @old_mov_ubiorigen int
declare @old_mov_ubidestino int
declare @old_mov_documento char(10)
declare @old_mov_descripcion char(10)

declare @errno int
declare @errmsg char(255)
declare @numrows int

declare @v_ubi_id int
declare @v_obj_codigo char(10)
declare @v_ubi_fecha datetime
declare @v_mov_fecha datetime
declare @v_mov_ubidestino int
declare @v_mov_mto int
declare @variable char(10)
declare @flag_valor int


select
@new_mov_mto = inserted.mov_mto,
@new_obj_codigo = inserted.obj_codigo,
@new_mov_fecha = inserted.mov_fecha,
@new_mov_ubiorigen = inserted.mov_ubiorigen,
@new_mov_ubidestino = inserted.mov_ubidestino,
@new_mov_documento = inserted.mov_documento,
@new_mov_ubidestino = inserted.mov_ubidestino,
@new_mov_descripcion = inserted.mov_descripcion
from inserted

select
@old_mov_mto = deleted.mov_mto,
@old_obj_codigo = deleted.obj_codigo,
@old_mov_fecha = deleted.mov_fecha,
@old_mov_ubiorigen = deleted.mov_ubiorigen,
@old_mov_ubidestino = deleted.mov_ubidestino,
@old_mov_documento = deleted.mov_documento,
@old_mov_ubidestino = deleted.mov_ubidestino,
@old_mov_descripcion = deleted.mov_descripcion
from deleted



select @v_ubi_fecha = obj_fecbaja
from Objetos
where obj_codigo=@old_obj_codigo


if @v_ubi_fecha is not null BEGIN
set @errno = -1002
set @errmsg = 'Este objeto esta dado de baja, no se puede
modificar ni eliminar.'
RAISERROR ( @errmsg,16,1)
goto on_error
END
select @v_mov_mto=max (MOV_MTO)
from MOVIMIENTOS
WHERE obj_codigo = @old_obj_codigo
group by obj_codigo

if @old_mov_mto < @v_mov_mto begin
set @errno = -1002
set @errmsg = 'No se pueden eliminar el movimiento, hay movimientos
posteriores.'
RAISERROR ( @errmsg,16,1)
goto on_error
end

else begin

update UBICACIONES
set obj_codigo=null
where obj_codigo=@old_obj_codigo


update UBICACIONES
set obj_codigo=@old_obj_codigo
where ubi_id=@old_mov_ubiorigen

end
end

end
EXECUTE p_identitymov @OLD_mov_mto



GoTo fim
on_error:
if @@error <> 0 begin
rollback transaction
end
fim:


-

Es decir, cuando yo elimino un movimiento, este actualiza la tabla
ubicaciones ESTO FUNCIONA PERFECTAMENTE.

El problema es si desde el analizador de consutlas hago:

delete from movimiento


ya que sólo salta el trigger en el último registro y si este se puede
eliminar se me eliminan todos los registros, si no se puede eliminar
ya que esta el objeto dado de baja o no es el ultimo me genera el
mensaje de error y se cancela todo.

De todas formas, si se hiciera bien el delete me actualizaría la tabla
ubicaciones, pero no lo hace.

Lo que necesito que que si yo escribo : "delete from movimiento " y
tengo 1938 registros, que el trigger salte 1938 veces y me actualice
la tabla ubicaciones cada vez y si el número 52 que va a eliminar
esta dado de baja lo cancele todo.

Por lo que veo la única forma es utilizando cursores ya que no
encuentro otra manera o ¿si que la hay?????



Gracias.
Respuesta Responder a este mensaje
#20 Liliana Sorrentino
23/06/2004 - 19:07 | Informe spam
Celeste,
Mañana, cuando lo pruebes, "con la fresca" como decimos acá, releé bien
todos los mensajes que recibiste, tal vez puedas entender que si tu
sentencia DELETE afecta MAS de una fila, realizará TODO por cada fila
eliminada.
Esto es, controlará la baja, controlará movimientos posteriores y
actualizará Ubicaciones, por CADA fila de Movimientos que se elimine.
Si no se puede eliminar ALGUNA, NO HARÁ NADA, tampoco en Ubicaciones.

Saludos... Liliana.

Ulises, tu trigger quedó más lindo que el que yo estaba terminando...
gracias.

"Celeste" escribió en el mensaje
news:
GRACIAS ESO ES LO QUE NECESITABA.

Gracias por aclarme que el trigger se lanza 1 vez en cada sentencia.

Pero esto no me vale ya que lo que yo tengo son dos tablas ubicacioens y
movimetos que tienen que estar actualizadas entre ellas, si yo elimino 2
registros tengo que entrar dos veces en el trigger y realizar lo que esta
escribo dentro PERO DOS VECES.

Por lo tanto la comprobacion de si he dado de baja si que me vale, pero


lo
de controlar ubicaciones-movimietnos no me vale, asi que creo que con lo


que
me has contado (que se lanza 1 vez en cada sentencia) voy a realizar un
cursor (si no me comentas nada mas).

Pero eso será mañana que lo probaré todo.


Saudos.




Respuesta Responder a este mensaje
Ads by Google
Help Hacer una preguntaSiguiente AnteriorRespuesta Tengo una respuesta
Search Busqueda sugerida