How can i use information from another table in a trigger? - sql

I tried this, but it didn't work. I wanted to use the "valor" row to make this trigger.
CREATE TRIGGER valor_total ON Detalhe_Venda
AFTER INSERT
AS
DECLARE #vendaid INT
DECLARE #produtoid INT
DECLARE #qtd_produtos INT
DECLARE #valor FLOAT
SELECT #vendaid = venda_id, #produtoid = produto_id, #qtd_produtos = quantidadeprod
FROM INSERTED
SELECT #valor = valor
FROM Produtos
WHERE id = #produtoid
UPDATE Venda
SET valortotal = valortotal + (#valor * #qtd_produtos)
WHERE id = #vendaid

You are misunderstanding a lot of things about triggers in SQL Server. The most important is that INSERTED is a set of rows, not a single row.
In fact, you can simplify your whole trigger to a single query:
CREATE TRIGGER valor_total ON Detalhe_Venda
AFTER INSERT
AS
BEGIN
UPDATE v
SET valortotal = v.valortotal + (p.valor * i.quantidadeprod)
FROM Venda v JOIN
Inserted i
ON v.id = i.venda_id JOIN
Produtos p
ON p.id = i.produtoid;
END;
EDIT:
SMore makes a good point. Aggregation is probably desirable before the join:
CREATE TRIGGER valor_total ON Detalhe_Venda
AFTER INSERT
AS
BEGIN
UPDATE v
SET valortotal = v.valortotal + ip.valor
FROM Venda v JOIN
(SELECT i.venda_id,
SUM(p.valor * i.quantidadeprod) as valor
FROM Inserted i JOIN
Produtos p
ON p.id = i.produtoid
GROUP BY i.venda_id
) ip
ON v.id = ip.venda_id
END;

Related

SQL Update trigger requirement

I want to write a trigger which updates some fields in another master table record in TRN_PT_TESTS_DET table gets updated for a specific test.
EG. when driving license in PTD_READING_TEXT column is updated in TRN_PT_TESTS_DET table, we want to update PT_DRIVER_LIC column in MST_PATIENT where PT_ID = ENC_PT_ID, which will also look in TST_CODE = 'SC32105' in MST_TESTS table (code 'SC32105' stands for driving license).
Reference query:
select top 10 ENC_PT_ID, PTD_READING_TEXT
from trn_pt_tests_Det
inner join trn_pt_tests_head on ptd_pth_id = pth_id
inner join trn_encounters on pth_enc_id = enc_id
where ptd_test_id = (select TST_ID from MST_TESTS where TST_CODE = 'SC32105');
While doing that we also want to add a record in TRN_NOTES with TN_TYPE = 'PC', TN_OBJECT_ID = PT_ID and TN_NOTE =
"Updated Patient <PT_LAST_NAME>, <PT_FIRST_NAME> Driver License Old:XXX New:YYYY"
I have created a below trigger which is not updating the PT_DRIVER_LIC column in MST_PATIENT and also inserting incorrect record into TRN_NOTES table.
Can someone please tell me what I am doing wrong?
When I execute below update query.
update TRN_PT_TESTS_DET
set PTD_READING_TEXT = 'aaaaa'
where PTD_TEST_ID = 11025
and PTD_PTH_ID = 134
the value is updated and trigger is called but #pt_id, #enc_id, #pt_last_name and #pt_first_name declared variable in trigger fetch different ID's and insert different values in TRN_NOTES table and the update MST_PATIENT table part don't work at all.
Can some please review below trigger and help me to fin out what I am doing wrong.
Trigger:
CREATE TRIGGER update_driver_lic_and_notes
ON TRN_PT_TESTS_DET
AFTER UPDATE
AS
IF (UPDATE (PTD_READING_TEXT))
BEGIN
IF EXISTS (SELECT 1
FROM trn_pt_tests_Det
INNER JOIN trn_pt_tests_head ON ptd_pth_id = pth_id
INNER JOIN trn_encounters ON pth_enc_id = enc_id
WHERE PTH_ID = PTD_PTH_ID
AND EXISTS (SELECT 1
FROM MST_TESTS
WHERE TST_CODE = 'VTWTLBS'))
BEGIN
DECLARE #old_dl varchar(255);
DECLARE #new_dl varchar(255);
DECLARE #pt_id int;
DECLARE #enc_id int;
DECLARE #pt_last_name varchar(255);
DECLARE #pt_first_name varchar(255);
SELECT #old_dl = PT_DRIVER_LIC
FROM MST_PATIENT
INNER JOIN trn_encounters ON PT_ID = ENC_PT_ID
INNER JOIN trn_pt_tests_head ON pth_enc_id = enc_id
INNER JOIN TRN_PT_TESTS_DET ON ptd_pth_id = pth_id
WHERE ptd_test_id = (SELECT TST_ID FROM MST_TESTS
WHERE TST_CODE = 'VTWTLBS');;
SELECT #new_dl = PTD_READING_TEXT,
#pt_id = ENC_PT_ID,
#enc_id = enc_id,
#pt_last_name = PT_LNAME,
#pt_first_name = PT_FNAME
FROM MST_PATIENT
INNER JOIN trn_encounters ON PT_ID = ENC_PT_ID
INNER JOIN trn_pt_tests_head ON pth_enc_id = enc_id
INNER JOIN TRN_PT_TESTS_DET ON ptd_pth_id = pth_id
WHERE ptd_test_id = (SELECT TST_ID FROM MST_TESTS
WHERE TST_CODE = 'VTWTLBS');
-- IF (#old_dl != #new_dl)
UPDATE MST_PATIENT
SET PT_DRIVER_LIC = #new_dl
WHERE PT_ID = #pt_id;
INSERT INTO TRN_NOTES (TN_TYPE, TN_OBJECT_ID, TN_ENC_ID, TN_MOD_USER, TN_NOTES, TN_MOD_TIMESTAMP)
VALUES ('PC', #pt_id, #enc_id,0, 'Updated Patient ' + #pt_last_name + ', ' + #pt_first_name + ' Driver License Old:' + #old_dl + ' New:' + #new_dl, GETDATE());
END
END
Thank you.

SQL - After insert Same Table

So I understand recursive triggers. Got to be careful of deadlocks etc. However this is only after an insert not after insert and update. Also, I have an audit trigger table that I am updating to make sure all is well. And querying after to double check. All looks fine but no update happens.
if exists (select 'a' from sys.triggers where name = 'invoicememologic')
begin
drop trigger invoicememologic
end
go
create trigger invoicememologic
on transactiontable
after insert
as
begin
declare #inum varchar(1000)
select #inum = min(transactioninvnum)
from
(select transactioninvnum
from inserted i
inner join project p on left(i.projectid, charindex(':', i.projectid)) = p.projectid
where right(i.projectid, 1) <> ':'
and abs(p.UseProjectMemoOnInv) = 1
group by transactioninvnum) b
while #inum is not null
begin
declare #rCount int
select #rCount = count(*)
from transactiontable
where TransactionInvNum = #inum
if #rCount = 1
begin
declare #tid varchar(100)
select #tid = transactionid
from transactiontable
where TransactionInvNum = #inum
declare #pmemo varchar(MAX)
select #pmemo = p.projectMemo
from transactiontable tt
inner join project p on left(tt.projectid, charindex(':', tt.projectid)) = p.projectid
where transactionInvNum = #inum
insert into audittrigger
values (#pmemo, #tid)
update transactiontable
set transactionmemo2 = #pmemo
where ltrim(rtrim(transactionid)) = ltrim(rtrim(#tid))
end
select #inum = min(transactioninvnum)
from
(select transactioninvnum
from inserted i
inner join project p on left(i.projectid, charindex(':', i.projectid)) = p.projectid
where abs(transactionjointinv) = 1
and right(i.projectid, 1) <> ':'
and abs(p.UseProjectMemoOnInv) = 1
group by transactioninvnum ) a
where transactioninvnum > #inum
end
end
Reason for trigger. 1 Invoice can be multiple rows in the database. 3 rows. So it only should update any one of the 3 rows. Doesn't matter. And it must grab the memo from the parent project of the phases that are being inserted into the database. hence the inner join on the left with charindex.
So I check the audit table. All looks well there. MEMO is there and the transactionid is there. I query after the trigger fires. TransactionID exists in the transactiontable but the memo2 is not being updated.
TransactionMemo2 is type of ntext. I thought it might be varchar with a direct update command will fail. I tried to update manually through setting a var as the text string and call the update manually with the transactionid being required. all worked fine. I am lost

SQL Server Multi-row insert trigger

I have tested that trigger but it works only with one insert row.
The trigger fails with multiple-row insert and I didn't find the syntax to fix the trigger.
Any suggestion to fix that?
Thanks to the stackoverflow users that let me notice the problem.
USE [MY_DB]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[tr_update_father]
ON [dbo].[PROD_IVR_CALL]
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
DECLARE #tnumber nvarchar(50), #id_inserted int, #id_prod_file int;
select
#id_inserted = ins.id,
#tnumber = ins.tnumber ,
#id_prod_file = pf.ID_PROD_FILE
from inserted ins
inner join prod_failure pf on (ins.ID_PROD_FAILURE = pf.ID);
update prod_ivr_call
set id_father = sq.ID
from
(select min(pic.id) as ID
from prod_ivr_call pic
inner join prod_failure pf on (pic.ID_PROD_FAILURE = pf.ID)
where pic.tnumber = #tnumber
and pic.is_requested = 0
and pf.ID_PROD_FILE = #id_prod_file
group by pic.tnumber ) sq
END
Your UPDATE statement is not syntactically correct. You can actually merge the two statements of your trigger using a CTE, and then do the UPDATE on this CTE:
ALTER TRIGGER [dbo].[tr_update_father]
ON [dbo].[PROD_IVR_CALL]
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
;WITH ToUpdate AS (
SELECT pic.id_father,
MIN(pic.id) OVER (PARTITION BY pic.tnumber) AS min_id
FROM prod_ivr_call pic
INNER JOIN join prod_failure pf ON pic.ID_PROD_FAILURE = pf.ID
JOIN inserted ins ON ins.ID_PROD_FAILURE = pf.ID
WHERE pic.tnumber = ins.tnumber AND pic.is_requested = 0
)
UPDATE ToUpdate
SET id_father = min_id
END

SQL Server Trigger not Working

i have this 2 triggers and no one is working, but i dont know why, canĀ“t everyone help me:
Insert:
CREATE TRIGGER [dbo].[afterInsert]
ON [dbo].[LinhasVenda]
FOR INSERT
AS
BEGIN
DECLARE
#IdVenda INT,
#PrecoTotalSIva MONEY,
#PrecoTotalCIva MONEY
SELECT
#PrecoTotalSIva = PrecoTotalSIva,
#PrecoTotalCIva = PrecoTotalCIva
FROM
INSERTED
UPDATE Vendas SET ValorSIva = ValorSIva + #PrecoTotalSIva,
ValorCIva = ValorCIva + #PrecoTotalCIva WHERE
IdVenda = #IdVenda
END
Delete:
CREATE TRIGGER afterDelete
ON LinhasVenda
FOR DELETE
AS
BEGIN
DECLARE
#IdVenda INT,
#IdArtifo INT,
#PrecoTotalSIva MONEY,
#PrecoTotalCIva MONEY
SELECT
#PrecoTotalSIva = PrecoTotalSIva,
#PrecoTotalCIva = PrecoTotalCIva
FROM
DELETED
UPDATE Vendas SET ValorSIva = ValorSIva - #PrecoTotalSIva,
ValorCIva = ValorCIva - #PrecoTotalCIva WHERE
IdVenda = #IdVenda
END
Both triggers have 2 flaws. The #IdVenda value used in the WHERE clause is not being assigned by the SELECT statements. Also, these triggers will not work with multi-row INSERT/UPDATE statements. I suggest you JOIN to INSERTED/DELETED, which will address both these problems. Below is an example, assuming the column name in the LinhasVenda table is also named IdVenda.
CREATE TRIGGER [dbo].[afterInsert]
ON [dbo].[LinhasVenda]
FOR INSERT
AS
BEGIN
UPDATE v
SET
ValorSIva = v.ValorSIva + i.PrecoTotalSIva
, ValorCIva = v.ValorCIva + i.PrecoTotalCIva
FROM Vendas AS v
JOIN INSERTED AS i ON
i.IdVenda = v.IdVenda;
END;
GO
CREATE TRIGGER afterDelete
ON LinhasVenda
FOR DELETE
AS
BEGIN
UPDATE v
SET
ValorSIva = v.ValorSIva - d.PrecoTotalSIva
, ValorCIva = v.ValorCIva - d.PrecoTotalCIva
FROM Vendas AS v
JOIN DELETED AS d ON
d.IdVenda = v.IdVenda;
END;
GO

SQL Server Update trigger for bulk updates

Below is a SQL Server 2005 update trigger. For every update on the email_subscriberList table where the isActive flag changes we insert an audit record into the email_Events table. This works fine for single updates but for bulk updates only the last updated row is recorded. How do I convert the below code to perform an insert for every row updated?
CREATE TRIGGER [dbo].[Email_SubscriberList_UpdateEmailEventsForUpdate_TRG]
ON [dbo].[Email_subscriberList]
FOR UPDATE
AS
DECLARE #CustomerId int
DECLARE #internalId int
DECLARE #oldIsActive bit
DECLARE #newIsActive bit
DECLARE #email_address varchar(255)
DECLARE #mailinglist_name varchar(255)
DECLARE #email_event_type varchar(1)
SELECT #oldIsActive = isActive from Deleted
SELECT #newIsActive = isActive from Inserted
IF #oldIsActive <> #newIsActive
BEGIN
IF #newIsActive = 1
BEGIN
SELECT #email_event_type = 'S'
END
ELSE
BEGIN
SELECT #email_event_type = 'U'
END
SELECT #CustomerId = customerid from Inserted
SELECT #internalId = internalId from Inserted
SELECT #email_address = (select email from customer where customerid = #CustomerId)
SELECT #mailinglist_name = (select listDescription from Email_lists where internalId = #internalId)
INSERT INTO Email_Events
(mailshot_id, date, email_address, email_event_type, mailinglist_name)
VALUES
(#internalId, getDate(), #email_address, #email_event_type,#mailinglist_name)
END
example
untested
CREATE TRIGGER [dbo].[Email_SubscriberList_UpdateEmailEventsForUpdate_TRG]
ON [dbo].[Email_subscriberList]
FOR UPDATE
AS
INSERT INTO Email_Events
(mailshot_id, date, email_address, email_event_type, mailinglist_name)
SELECT i.internalId,getDate(),c.email,
case i.isActive when 1 then 'S' else 'U' end,e.listDescription
from Inserted i
join deleted d on i.customerid = d.customerid
and i.isActive <> d.isActive
join customer c on i.customerid = c.customerid
join Email_lists e on e.internalId = i.internalId
Left outer joins, for in case there are no related entries in customer or email_Lists (as is possible in the current code) -- make them inner joins if you know there will be data present (i.e. foreign keys are in place).
CREATE TRIGGER [dbo].[Email_SubscriberList_UpdateEmailEventsForUpdate_TRG]
ON [dbo].[Email_subscriberList]
FOR UPDATE
AS
INSERT INTO Email_Events
(mailshot_id, date, email_address, email_event_type, mailinglist_name)
select
i.InternalId
,getdate()
,cu.Email
,case i.IsaActive
when 1 then 'S'
else 'U'
end
,el.ListDescription
from inserted i
inner join deleted d
on i.CustomerId = d.CustomerId
and i.IsActive <> d.IsActive
left outer join Customer cu
on cu.CustomerId = i.CustomerId
left outer join Email_Lists el
on el.InternalId = i.InternalId
Test it well, especially for concurrency issues. Those joins within the trigger make me nervous.