Only run trigger if value is FALSE - sql-server

After some trial and error, along with your help, I have come up with the following code for my trigger:
ALTER TRIGGER [dbo].[SnapChapas]
ON [dbo].[Tab_Inventarios_Chapas]
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
IF UPDATE(Ativo)
DECLARE #IDInventario as INT
SET #IDInventario = (SELECT ID FROM inserted)
INSERT
INTO Tab_Inventarios_Chapas_Snap_Banco
( ID_Tab_Chapas,
FormatoL,
Comprimento1,
Comprimento2,
Largura1,
Largura2,
Quantidade,
ID_Tab_Inventarios_Chapas
)
SELECT ID,
FormatoL,
Comprimento1,
Comprimento2,
Largura1,
Largura2,
Quantidade,
#IDInventario
FROM Tab_Chapas
The code above is working. My problem here is: I Have a column called "ACTIVE" in [dbo].[Tab_Inventarios_Chapas]. I need the trigger to only run if the updated value is FALSE.
P.S.: My Application only updates one line at a time; there’s no way to update more than one.

Thanks to #JeroenMostert, I could find an answer.
Here is my final code:
ALTER TRIGGER [dbo].[SnapChapas]
ON [dbo].[Tab_Inventarios_Chapas]
AFTER UPDATE
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
Declare #ativo as bit
Set #ativo = (select Ativo from inserted)
if UPDATE(Ativo) and #ativo='False'
declare #IDInventario as int
Set #IDInventario = (select ID from inserted)
insert into Tab_Inventarios_Chapas_Snap_Banco (ID_Tab_Chapas,FormatoL,Comprimento1,Comprimento2,Largura1,Largura2,Quantidade,ID_Tab_Inventarios_Chapas)
select ID,FormatoL,Comprimento1,Comprimento2,Largura1,Largura2,Quantidade,#IDInventario
from Tab_Chapas
END
Thank You!

Related

SQL Trigger Inconsistently firing

I have a SQL Trigger on a table that works... most of the time. And I cannot figure out why sometimes the fields are NULL
The trigger works by Updateing the LastUpdateTime whenever something is modified in the field, and the InsertDatetime when first Created.
For some reason this only seems to work some times.
ALTER TRIGGER [dbo].[DateTriggerTheatreListHeaders]
ON [dbo].[TheatreListHeaders]
AFTER INSERT,UPDATE
AS
BEGIN
SET NOCOUNT ON;
IF NOT EXISTS(SELECT * FROM DELETED)
BEGIN
UPDATE ES
SET InsertDatetime = Getdate()
,LastUpdateDateTime = Getdate()
FROM TheatreListHeaders es
JOIN Inserted I ON es.UNIQUETHEATRELISTNUMBER = I.UNIQUETHEATRELISTNUMBER
END
IF UPDATE(LastUpdateDateTime) OR UPDATE(InsertDatetime)
RETURN;
IF EXISTS (
SELECT
*
FROM
INSERTED I
JOIN
DELETED D
-- make sure to compare inserted with (same) deleted person
ON D.UNIQUETHEATRELISTNUMBER = I.UNIQUETHEATRELISTNUMBER
)
BEGIN
UPDATE ES
SET InsertDatetime = ISNULL(es.Insertdatetime,Getdate())
,LastUpdateDateTime = Getdate()
FROM TheatreListHeaders es
JOIN Inserted I ON es.UNIQUETHEATRELISTNUMBER = I.UNIQUETHEATRELISTNUMBER
END
END
A much simpler and efficient approach to do what you are trying to do, would be something like...
ALTER TRIGGER [dbo].[DateTriggerTheatreListHeaders]
ON [dbo].[TheatreListHeaders]
AFTER INSERT,UPDATE
AS
BEGIN
SET NOCOUNT ON;
--Determine if this is an INSERT OR UPDATE Action .
DECLARE #Action as char(1);
SET #Action = (CASE WHEN EXISTS(SELECT * FROM INSERTED)
AND EXISTS(SELECT * FROM DELETED)
THEN 'U' -- Set Action to Updated.
WHEN EXISTS(SELECT * FROM INSERTED)
THEN 'I' -- Set Action to Insert.
END);
UPDATE ES
SET InsertDatetime = CASE WHEN #Action = 'U'
THEN ISNULL(es.Insertdatetime,Getdate())
ELSE Getdate()
END
,LastUpdateDateTime = Getdate()
FROM TheatreListHeaders es
JOIN Inserted I ON es.UNIQUETHEATRELISTNUMBER = I.UNIQUETHEATRELISTNUMBER;
END
"If update()" is poorly defined/implemented in sql server IMO. It does not do what is implied. The function only determines if the column was set by a value in the triggering statement. For an insert, every column is implicitly (if not explicitly) assigned a value. Therefore it is not useful in an insert trigger and difficult to use in a single trigger that supports both inserts and updates. Sometimes it is better to write separate triggers.
Are you aware of recursive triggers? An insert statement will execute your trigger which updates the same table. This causes the trigger to execute again, etc. Is the (database) recursive trigger option off (which is typical) or adjust your logic to support that?
What are your expectations for the insert/update/merge statements against this table? This goes back to your requirements. Is the trigger to ignore any attempt to set the datetime columns directly and set them within the trigger always?
And lastly, what exactly does "works sometimes" actually mean? Do you have a test case that reproduces your issue. If you don't, then you can't really "fix" the logic without a specific failure case. But the above comments should give you sufficient clues. To be honest, your logic seems to be overly complicated. I'll add that it also is logically flawed in the way that it set insertdatetime to getdate if the existing value is null during an update. IMO, it should reject any update that attempts to set the value to null because that is overwriting a fact that should never change. M.Ali has provided an example that is usable but includes the created timestamp problem. Below is an example that demonstrates a different path (assuming the recursive trigger option is off). It does not include the rejection logic - which you should consider. Notice the output of the merge execution carefully.
use tempdb;
set nocount on;
go
create table zork (id integer identity(1, 1) not null primary key,
descr varchar(20) not null default('zippy'),
created datetime null, modified datetime null);
go
create trigger zorktgr on zork for insert, update as
begin
declare #rc int = ##rowcount;
if #rc = 0 return;
set nocount on;
if update(created)
select 'created column updated', #rc as rc;
else
select 'created column NOT updated', #rc as rc;
if exists (select * from deleted) -- update :: do not rely on ##rowcount
update zork set modified = getdate()
where exists (select * from inserted as ins where ins.id = zork.id);
else
update zork set created = getdate(), modified = getdate()
where exists (select * from inserted as ins where ins.id = zork.id);
end;
go
insert zork default values;
select * from zork;
insert zork (descr) values ('bonk');
select * from zork;
update zork set created = null, descr = 'upd #1' where id = 1;
select * from zork;
update zork set descr = 'upd #2' where id = 1;
select * from zork;
waitfor delay '00:00:02';
merge zork as tgt
using (select 1 as id, 'zippity' as descr union all select 5, 'who me?') as src
on tgt.id = src.id
when matched then update set descr = src.descr
when not matched then insert (descr) values (src.descr)
;
select * from zork;
go
drop table zork;

Insert after event trigger in SQL Server

I need to create a trigger in SQL Server for filling a table if an event is done.
My code:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[Tr_EsportaMancatiContatti]
ON [dbo].[Lav_CollaudiVodaf_StoricoMancatiContatti]
AFTER INSERT
AS
BEGIN
DECLARE #IDPRATStorico INT;
DECLARE #IDPRAT INT;
DECLARE #CodRichiestaCRM INT;
DECLARE #IDESITO INT;
DECLARE #Telefono VARCHAR;
DECLARE #DataOraContatto INT;
SET NOCOUNT ON;
SET #IDPRATStorico = (SELECT IDPRATStorico FROM inserted);
SET #IDPRAT = (SELECT IDPRAT FROM inserted);
SET #CodRichiestaCRM = (SELECT CodRichiestaCRM FROM inserted);
SET #IDESITO = (SELECT IDESITO FROM inserted);
SET #Telefono = (SELECT Telefono FROM inserted);
SET #DataOraContatto = (SELECT DataOraContatto FROM inserted);
IF #IDESITO = 18 AND count(#IDPRAT) < 3
BEGIN
INSERT Lav_CollaudiVodaf_StoricoMancatiContatti
SET IDPRATStorico=#IDPRATStorico
SET CodRichiestaCRM=#CodRichiestaCRM
SET IDESITO=#IDESITO
SET Telefono=Telefono
SET DataOraContatto=#DataOraContatto
WHERE IdPrat=#IDPRAT;
END
END;
It throws some error.
Target: I have a table filled with contacts, I need to insert these record into another table, if the IDESITO is 18 and the count in the new table is < 3.
Any suggestion is appreciated.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[Tr_EsportaMancatiContatti]
ON [dbo].[Lav_CollaudiVodaf_StoricoMancatiContatti]
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO Lav_CollaudiVodaf_StoricoMancatiContatti(
IDPRATStorico,
CodRichiestaCRM,
IDESITO,
Telefono,
DataOraContatto
)
SELECT TOP 3
IDPRATStorico,
CodRichiestaCRM,
IDESITO,
Telefono,
DataOraContatto
FROM INSERTED
WHERE IDESITO = 18
END;
I am not sure what you are trying to achieve with count(#IDPRAT) < 3. I guess you might want only the top 3 rows

how to check data if exists "type of table" in stored procedure

I have created a type in sql server 2008 for to pass datatable to stored procedure.
My SP works ok but how can I check data if exists in the table?
(for example: check detailid or id
if exists: update them
if not exists: insert new )
here is my SP:
ALTER PROCEDURE [dbo].[Insert_Data]
(
#empinfo myType READONLY
)
AS
BEGIN
SET NOCOUNT ON;
Insert into TableEmp(ID, DetailID, Text)
select id, detailid, text from #empinfo
END
Thnx all
ALTER PROCEDURE [dbo].[Insert_Data]
(
#empinfo myType READONLY
)
AS
BEGIN
SET NOCOUNT ON;
MERGE TableEmp AS t
USING (select id, detailid, [text] from #empinfo) AS s
ON s.ID = t.ID
WHEN MATCHED THEN
UPDATE SET t.detailid = s.detailid,
t.[text] = s.[text]
WHEN NOT MATCHED THEN
INSERT(id, detailid, [text])
VALUES(s.id, s.detailid, s.[text]);
END
You can declare a variable and count the records in the table.
DECLARE #count INT
SET #count = (SELECT COUNT(ID)
FROM TableEmp)
-- Do Something with the results
So then using conditional logic, you can do something with the count to accomplish different results.
IF #count = 0
BEGIN
-- Do Something cool like insert data
END
ELSE
BEGIN
-- Do Something else like update data
END
This is a simple example where you can search for a specific record and update it. If you need to update many records, then you can use cursors and iterate through the required records and update what you need.
More information about cursors can be found here:
http://technet.microsoft.com/en-us/library/ms180169.aspx

sql trigger cannot insert row using variable

When i use this code it inserts row
create trigger [dbo].[InsertInvPayment] on dbo.LG_001_01_PAYTRANS
after update
as
begin
SET NOCOUNT ON;
declare #InvLogicalRef int;
declare #InvNumber varchar(50);
select #InvLogicalRef = inserted.FICHEREF from inserted
select #InvNumber = dbo.LG_001_01_INVOICE.DOCODE from dbo.LG_001_01_INVOICE where dbo.LG_001_01_INVOICE.LOGICALREF = #InvLogicalRef
insert into dbo.CRMINVPAYMENT(INVNUMBER) values('Hello')
end
if i change it like this
create trigger [dbo].[InsertInvPayment] on dbo.LG_001_01_PAYTRANS
after update
as
begin
SET NOCOUNT ON;
declare #InvLogicalRef int;
declare #InvNumber varchar(50);
select #InvLogicalRef = inserted.FICHEREF from inserted
select #InvNumber = dbo.LG_001_01_INVOICE.DOCODE from dbo.LG_001_01_INVOICE where dbo.LG_001_01_INVOICE.LOGICALREF = #InvLogicalRef
insert into dbo.CRMINVPAYMENT(INVNUMBER) values(#InvNumber)
end
it doesn't work. i couldn't find a mistake in the second
Seems like You are missing the source for select InvLogicalRef. It should be
select #InvLogicalRef = inserted.FICHEREF from inserted
Also with this trigger you are assuming that only one record will update at once. This will fail for bulk updates.
The line where you assign a value to #InvLogicalRef is incomplete.
As that variable doesn't contain a value, #InvNumber can't be assigned its value and you are therefore trying to insert a NULL string into CRMINVPAYMENT.
Make sure you select the value of #InvLogicalRef from the inserted table.

Efficiently return a value from a stored procedure

I have query which returns single value (i.e) count. I'm exceuting it using the stored procedure in the following way and using execute reader with dataset to get single value
CREATE PROCEDURE GetCnt
#EmpNo char(4)
AS
BEGIN
SET NOCOUNT ON;
Declare #Cnt int
SELECT #Cnt = count(*)
FROM employees
WHERE EMPLNO = #EmpNo
AND test = 'p'
BEGIN
SELECT #Cnt
END
END
is this effcient way
or Do I need to use the execute.scalar() and return value directly from the query instead of assigning to #cnt
can any one advise me
All ExecuteScalar does is get the first field from the first record.
Can't you just SELECT the count directly?
BEGIN
SET NOCOUNT ON
SELECT Count(*) FROM employees WHERE EMPLNO = #EmpNo AND test='p'
END
You do not need to create the variable. You just need the following:
CREATE PROCEDURE GetCnt
#EmpNo char(4)
AS
BEGIN
SET NOCOUNT ON;
SELECT count(1)
FROM employees
WHERE EMPLNO = #EmpNo
AND test = 'p'
END
Since this is only one value being returned from the stored procedure, you will likely want to use ExecuteScalar()

Resources