2010-08-26 208 views
22

tengo la mesa Tb¿Cómo puedo editar los valores de un INSERT en un desencadenador en SQL Server?

ID | Name | Desc 
------------------------- 
1 | Sample | sample desc 

Quiero crear un disparador en INSERT que cambiará el valor de la Desc insertando, por ejemplo:

INSERT INTO Tb(Name, Desc) VALUES ('x', 'y') 

resultará en

ID | Name | Desc 
------------------------- 
1 | Sample | sample desc 
2 | x  | Y edited 

En el ejemplo anterior obtuve el valor de la inserción Desc lo cambié a mayúscula y una dded edited en el extremo.

Eso es lo que necesito, obtenga el Desc que se está insertando y modifíquelo.

¿Cómo puedo hacer eso?

¿Es mejor manejarlo después de la inserción con una actualización? ¿O hacer un disparador con INSTEAD OF INSERT y modificarlo cada vez que la estructura de la tabla cambie?

+1

¿No puedes hacer esto de otra manera? Personalmente odio cuando veo cosas extrañas sucediendo en los datos y finalmente me doy cuenta de que un disparador fantasma estaba haciendo algunas cosas –

+0

Lo usaré para solucionar un problema que proviene de un código al que no tengo acceso. Inserta la 'url' de un elemento, pero no elimina acentos ni caracteres especiales, haré que un desencadenador lo haga por mí. – BrunoLM

+1

Este no es un concepto tan difícil y me hace pensar que Microsoft no puede proporcionar una funcionalidad tan simple como en Oracle, donde puede modificar cualquier valor antes de insertar editando los valores: NEW. es decir, si quiero siempre asignar los nombres de usuario a la parte superior antes de insertarlos (suponiendo que no puedo hacerlo en el código por algún motivo), podría tener un desencadenante insert anterior que lo haga: NEW.nombredeusuario: = UPPER (: NEW.nombredeusuario)) Sin embargo, en el Servidor SQL, no puede hacer el equivalente con valores en la tabla temporal INSERTADA, y eso realmente apesta. – Jim

Respuesta

30

Utilice un disparador de inserción posterior. Únase desde la pseudo tabla inserted al Tb en la clave principal. Luego actualiza los valores de desc. Algo así como: (Pero no puede compilar)

CREATE TRIGGER TbFixTb_Trg 
ON Tb 
AFTER INSERT 
AS 
BEGIN 
    UPDATE Tb 
    SET DESC = SomeTransformationOf(i.DESC) 
    FROM Tb 
    INNER JOIN inserted i on i.Id = Tb.Id 
END 
GO 

Este disparador pasa después de la inserción ha sucedido, pero antes de la declaración se realiza insert. Entonces, los valores nuevos e incorrectos ya están colocados en la tabla de destino. Este desencadenador no tendrá que cambiar a medida que se agregan, eliminan, etc.

Advertencia Las restricciones de integridad se aplican antes de que se dispare el desencadenador posterior. Por lo tanto, no puede aplicar una restricción de verificación para imponer la forma adecuada de DESC. Porque eso haría que la declaración falle antes de que el desencadenante tenga la oportunidad de arreglar algo. (Comprueba este párrafo antes de confiar en ella Ha sido un tiempo desde que he escrito un disparador..)

+0

¡Además, esta solución no hará que los valores realmente insertados estén disponibles para la cláusula 'OUTPUT'! –

+0

¿Qué es "Trgt" en este contexto? – CodenameCain

+1

@CodenameCain Un error. Debe ser 'Tb' o la cláusula from debe ser' from Tb Trgt'. gracias por atrapar eso. –

3

Es posible que desee ver INSTEAD OF activadores.

CREATE TRIGGER Tb_InsteadTrigger on Tb 
INSTEAD OF INSERT 
AS 
BEGIN 
... 

Esto le permitirá manipular los datos antes de que entren en la tabla. El disparador es responsable de insertar los datos en la tabla.

24

No estoy seguro de dónde va a obtener el nuevo valor real para desc, pero supongo que lo obtendrá de otra tabla o algo así. Pero probablemente tengas una razón para querer hacerlo de esta manera, así que a continuación hay un ejemplo de cómo lo haría.

Lo que quiere se llama un gatillo INSTEAD OF INSERT, dispara en lugar de un inserto sobre la mesa con cada lógica que le da.

CREATE TRIGGER trgUpdateDesc 
ON Tb 
INSTEAD OF INSERT 
AS 
BEGIN 
    SET NOCOUNT ON; 
    INSERT INTO Tb (Name, [Desc]) 
    SELECT Name, [Desc] + 'edited' 
    FROM inserted 
END 
GO 

He duro codificado la palabra 'editado' en ese país, ya que no estoy seguro de que desea obtener el valor, pero se puede reemplazar fácilmente que con una variable o un valor de otra tabla.

Oh también asegurarse de que el poner el [] en torno a la descripción, ya que es una palabra clave en el servidor SQL (siglas de descendente)

Espero que ayude!

Editar:

Si desea que sea un poco más robusto para que no depende de la estructura de la tabla lo más que podría utilizar un desencadenador AFTER INSERT para simplemente actualiza ese campo como tal.

CREATE TRIGGER [dbo].[trgUpdateDesc] 
    ON [dbo].[Tb] 
    AFTER INSERT 
AS 
BEGIN 
    SET NOCOUNT ON; 
    UPDATE Tb 
    SET [Desc] = UPPER(inserted.[Desc]) + ' Edited' 
    FROM inserted INNER JOIN Tb On inserted.id = Tb.id 
END 
+0

Quiero obtener el valor del 'Desc' insertado y modificarlo. Debi decir eso. Voy a actualizar mi pregunta, lo siento por eso – BrunoLM

+0

¿Qué pasa si mi tabla cambia? Tendré que actualizar el disparador cada vez? ¿No hay otra manera de hacer eso? – BrunoLM

8

tabla de temperatura puede ayudar a utilizar INSTEAD OF INSERT gatillo, evitando de enumerar explícitamente todas las columnas de las tablas no relacionadas:

CREATE TRIGGER trgUpdateDesc 
    ON Tb 
    INSTEAD OF INSERT 
AS 
BEGIN 
    SET NOCOUNT ON; 
    select * into #tmp from inserted; 
    UPDATE #tmp SET Desc = Desc + 'edited' --where ...; 
    insert into Tb select * from #tmp; 
    drop table #tmp; 
END 

No será necesario corregir este código cuando se agreguen nuevas columnas a la tabla.

Pero ten cuidado con some additional overhead of temp tables.

También tenga en cuenta que SQL Server desencadena el disparo una vez para las operaciones DML masivas y debe correctly handle multi-row inserts.

+0

Esto produce el siguiente error: un valor explícito para la columna de identidad en la tabla 'Tb' solo se puede especificar cuando se utiliza una lista de columnas y IDENTITY_INSERT está activado. –

+1

@Anders, creo que este enfoque puede ser incompatible con las columnas [IDENTITY] (http://stackoverflow.com/questions/16766963/insert-record-to-sql-table-with-identity-column). Pero también puede intentar colocar esta columna en la tabla '# tmp' dentro del desencadenador. – Vadzim

Cuestiones relacionadas