SQL Trigger to send an email - sql-server

I need to créate a trigger in a SQL table to send an email if the inserted record meets certain conditions.
That is, I create the trigger in Table1 to send an email to X if in the inserted record the field IdCircuito= 53, IdTipoDoc = 45 and Gestor = 'Gest1'. Also, in the body of email message I want the value of a certain field of that inserted record to appear. I have done something like this but trigger always executes regardless of the inserted record:
CREATE TRIGGER dbo.SendEmail
ON dbo.TitulosDoc
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
IF EXISTS (SELECT 1 FROM TitulosDoc WHERE IdCircuito = 53 AND IdTipoDoc = 45 AND Gestor = 'Gest1')
BEGIN
EXEC msdb.dbo.sp_send_dbmail
#recipients = 'rsg#gmail.com',
#subject = 'New requeriment',
#body = 'It's a new requeriment: ';
END
END
GO
In body is where I want show a literal text with the value of the field of inserted record:
#body = 'It's a new requeriment: ' + TitulosDoc.NombreDocumento;
Can somebody help me? Thank you

To access the inserted row you need to select from INSERTED.
Try this:
CREATE TRIGGER dbo.SendEmail
ON dbo.TitulosDoc
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
DECLARE #NombreDocumento VARCHAR(MAX) = (SELECT INSERTED.NombreDocumento
FROM INSERTED
WHERE INSERTED.IdCircuito = 53
AND INSERTED.IdTipoDoc = 45
AND INSERTED.Gestor = 'Gest1')
IF #NombreDocumento IS NOT NULL
BEGIN
EXEC msdb.dbo.sp_send_dbmail
#recipients = 'rsg#gmail.com',
#subject = 'New requeriment',
#body = 'It''s a new requeriment: ' + #NombreDocumento;
END
END
GO

I would do what Sean Lange said... create a physical table called TempTitulosDoc, then insert your records to it that need to be sent through email. Do this in your trigger.
CREATE TRIGGER dbo.SendEmail
ON dbo.TitulosDoc
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
BEGIN
INSERT INTO TempTiulosDoc(field1, field2, EmailStatus)
SELECT field1, field2, 0 AS EmailStatus --Email NOT sent
FROM TitulosDoc
WHERE IdCircuito = 53 AND IdTipoDoc = 45 AND Gestor = 'Gest1'
END
END
GO
Create a stored procedure like this that loops through those records and sends an email. When done, update the TempTitlosDoc with a status of 1 signifying a sent email.
DECLARE #loopCount INT
DECLARE #field1 VARCHAR(10)
DECLARE #field2 VARCHAR(10)
DECLARE #EmailStatus int
--Create Temp Table
CREATE TABLE #Temp
(
id int not null identity,
field1 VARCHAR(10),
field2 VARCHAR(10),
EmailStatus int
)
--Insert Tasks to temp table
INSERT INTO #Temp (field1, field2, EmailStatus)
SELECT field1, field2, EmailStatus
FROM dbo.TempTiulosDoc
WHERE Status = 0
--Set a loopCount for while loop
SET #loopCount = 1
--Use the while loop to check if we have any Tasks left to send
while ( exists(SELECT id FROM #Temp WHERE id = #loopCount) )
BEGIN
--Get current record in temp table
SELECT #field1 = field1,
#field2 = field2,
#EmailStatus = EmailStatus
FROM #Temp
WHERE id = #loopCount
EXEC msdb.dbo.sp_send_dbmail
#recipients = 'rsg#gmail.com',
#subject = 'New requeriment',
#body = 'It''s a new requeriment: ' + #NombreDocumento;
--Update your work table with the status of 1 so it's not picked up again
UPDATE teq
SET teq.#EmailStatus = 1
FROM dbo.TempTiulosDoc teq
WHERE teq.id = #field1
SET #loopCount = #loopCount + 1
END

Related

Adding a duplicate number

I'm currently experiencing the following problem.
If you have a look at the below test case:
declare #Count int
, #id int = 777
declare #table table
( id int identity primary key
, JCid int
, line int
, udf float )
insert into #table (jcid,line,udf)
values
(777,1,1),
(777,2,2.1),
(777,3,2.2),
(777,4,2),
(777,5,3)
select
#Count = count(left(L.udf,1))
from #table L
where L.jcid = #id
group by left(L.udf,1)
having count(left(L.udf,1))>1
select #Count
When I run this, I get the desired results of 3, however upon developing the below trigger, I can't get the count to work out correctly:
create trigger kv_trg_JobLineNumberUpdate_AW on _btblJCTxLines
after insert, update
as
declare #LineNum float
, #OldLine float
, #id int
, #Count int
, #Err nvarchar(500)
set #Err = '--------------------------';
set #Err = #Err + #Err + CHAR(10);
set #Err = #Err + CHAR(10);
set #Err = #Err + 'You are not allowed to change this Line Number!';
select
#LineNum = iLineID
, #OldLine = isnull(ufJCTxCMLineNumber,0)
, #id = iJCMasterID
from inserted
select
#Count = count(left(L.ufJCTxCMLineNumber,1))
from _btblJCTxLines L
join inserted i on left(L.ufJCTxCMLineNumber,1) = left(i.ufJCTxCMLineNumber,1)
where L.iJCMasterID = #id
group by left(L.ufJCTxCMLineNumber,1)
having count(left(L.ufJCTxCMLineNumber,1))>1
begin
if #OldLine = 0
begin
if #Count >= 2
begin
update _btblJCTxLines
set ufJCTxCMLineNumber = cast(#LineNum as varchar)+'.'+cast(#Count as varchar)
from _btblJCTxLines L
join inserted on L.idJCTxLines = inserted.idJCTxLines
end
else
begin
update _btblJCTxLines
set ufJCTxCMLineNumber = #LineNum
from _btblJCTxLines L
join inserted on L.idJCTxLines = inserted.idJCTxLines
end
end
else
begin
select
#OldLine = deleted.ufJCTxCMLineNumber
, #LineNum = inserted.ufJCTxCMLineNumber
from inserted, deleted
if (#OldLine <> #LineNum)
begin
raiserror(#Err, 16, 1)
rollback tran
return;
end
end
end
go
The ufJCTxCMLineNumber field is the duplicate number I'm looking for.
This triggers main purpose is to ensure that the ufJCTxCMLineNumber field never has duplicates.
What happens is, a user inserts a new line, when they add a new line above any current line, I want the ufJCTxCMLineNumber field to be updated to 3.1 depending on how many duplicates there is.
How would I go about getting the correct count?
Follow this link for Sample Data.

SqlServer Trigger to add multiple rows

I have the following trigger:
ALTER TRIGGER .[dbo].[trgAfterInsertComment]
ON .[dbo].[Comment]
AFTER INSERT
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
declare #Id int;
declare #LoanId int;
declare #CopyId int;
declare #CustomerId int;
declare #Comment nvarchar(255);
--DECLARE cur CURSOR FOR
select #Id = Id from inserted
select #LoanId = LoanId from inserted
--select #CopyId = CopyId from deleted
--select #CustomerId = CustomerId from deleted
select #Comment = Comment from inserted
-- OPEN cur
--FETCH NEXT FROM cur INTO #Id, #ISBN, #Purchase_Date
--WHILE ##FETCH_STATUS = 0 BEGIN
-- your business logic
Declare #Title nvarchar(255);
select #Title = (Select Title from Book where ISBN = (select ISBN from copy where Id = (select CopyId from Loan where Id = #LoanId)))
select #CustomerId = (Select CustomerId from Loan where Id = #LoanId)
select #CopyId = (Select CopyId from Loan where Id = #LoanId)
insert into Activity("Heading", "Date")
values(Concat('New Comment added - Id: ', #Id, ' Title: ', #Title, ' Copy Id: ', #CopyId, ' Customer Id: ', #CustomerId, ' Comment: ', #Comment), GETDATE())
--FETCH NEXT FROM cur INTO #Id, #ISBN, #Purchase_Date
--END
--CLOSE cur
--DEALLOCATE cur
end
As you can see I have commented out a cursor that I was using to handle multiple inserts. Could someone tell me how I can handle multiple inserts without the cursor, as after reading around I see that using a cursor is a bad idea?
With the above trigger, if I try to insert multiple lines like this:
USE [Library]
GO
INSERT INTO [dbo].[Comment]
([LoanId]
,[Comment])
VALUES
(47, 'test'),
(48, 'test'),
(50, 'test')
GO
Only the first row is inserted into my Activity table. Thanks for any help
You need to shift it to be set based, using variables and a loop will cause you issues. Can't test the below, but something like:
INSERT INTO Activity
(
Heading ,
[Date]
)
SELECT CONCAT('New Comment added - Id: ', I.id, ' Title: ', COALESCE(B.Title,''), ' Copy Id: ', COALESCE(L.CopyID,''), ' Customer Id: ', COALESCE(L.CustomerID,'')) ,
GETDATE()
FROM inserted AS I
LEFT JOIN Loan AS L ON I.loanId = L.loanId
LEFT JOIN Copy AS C ON C.Id = L.CopyId
LEFT JOIN Book AS B ON B.ISBN = C.ISBN;
Do this querying inserted table directly.
insert into [dbo].[Comment] (LoanId, Comment)
select LoanId, Comment from inserted
You can change the select query to more complex to achieve the result using query only.

Trigger to handle multiple row inserts and updates

I am using the following trigger to track inserts and updates on multiple tables and log it in a log table.
CREATE TRIGGER tr_TestTable1]
ON [TestTable_1]
AFTER INSERT, UPDATE
AS
DECLARE #keyid int, #tn nvarchar(50), #recEditMode nvarchar(50), #trstat nvarchar(50)
BEGIN
SET NOCOUNT ON;
SET #tn = 'TestTable_1'
IF EXISTS(SELECT 1 FROM INSERTED)
BEGIN
SET #recEditMode = (Select REC_EDIT_MODE FROM inserted)
SET #trstat = 'PENDING'
SET #keyid = (Select prkeyId FROM inserted)
IF (#recEditMode = 'MANUAL')
BEGIN
IF NOT EXISTS (SELECT * FROM [logTable_1] WHERE SourceKeyId = #keyid AND TrStatus = 'PENDING' AND SourceTableName = #tn)
BEGIN
INSERT INTO [logTable_1](SourceKeyId,SourceTableName,TrStatus)
VALUES (#keyid, #tn, #trstat)
END
END
END
END
This works fine on single row insert and single row update. I am unable to optimize this code to handle multi row inserts and updates. Looking for some help in handling this.
Thanks.
I modified the trigger as below and it seems to be working fine now...
CREATE TRIGGER tr_TestTable1]
ON [TestTable_1]
AFTER INSERT, UPDATE
AS
DECLARE #keyid int, #tn nvarchar(50), #trstat nvarchar(50)
BEGIN
IF ##ROWCOUNT = 0
RETURN
SET NOCOUNT ON;
IF EXISTS(SELECT * FROM INSERTED)
BEGIN
SET #tn = 'TestTable_1'
SET #trstat = 'PENDING'
BEGIN
INSERT INTO LogTable_1 (SourceKeyId, SourceTableName, TrStatus)
SELECT I.prKeyId, #tn, #trStat FROM INSERTED AS I
WHERE (I.REC_EDIT_MODE = 'MANUAL' AND NOT EXISTS(SELECT * FROM LogTable_1 WHERE SourceKeyId = I.prKeyId AND SourceTableName = #tn AND TrStatus = 'PENDING'))
END
END
END

Cannot insert users in AspNetUsers table

I am trying to populate the AspNetUsers table using a stored procedure, but I get the following error:
Msg 515, Level 16, State 2, Procedure Insert_Users, Line 36 Cannot
insert the value NULL into column 'Id', table
'MyDatabase.dbo.AspNetUsers'; column does not allow nulls. INSERT
fails.
I read on some other posts that there should be the following attribute on the column Id: [DatabaseGenerated(DatabaseGeneratedOption.Identity)], but I cannot manage to find where is physically declared.
I don't want to insert all users manually because I'm out of time and I need to do it as quick as possible.
BEGIN
SET NOCOUNT ON;
DECLARE #id uniqueidentifier
DECLARE #email nvarchar(256)
DECLARE #emailconfirmed bit
SET #emailconfirmed = 0
DECLARE #twofactorenabled bit
SET #twofactorenabled = 0
DECLARE #lockoutenabled bit
SET #lockoutenabled = 1
DECLARE #accessFailed bit
SET #accessFailed = 1
DECLARE #username nvarchar(256)
DECLARE #fname nvarchar(50)
DECLARE #lname nvarchar(50)
DECLARE #athleteKey int
SET #athleteKey = 41809
DECLARE #atheletsCount int
SET #atheletsCount = 0;
SET #atheletsCount = (SELECT COUNT(*) FROM [BIBD].[dbo].[Athlete])
WHILE #athleteKey < #atheletsCount
SET #id = NEWID() --Line 36
print CAST(#id AS nvarchar(128))
SET #fname = (SELECT FirstName FROM [BIBD].[dbo].[Athlete] where AthleteKey=#athleteKey)
SET #lname = (SELECT LastName FROM [BIBD].[dbo].[Athlete] where AthleteKey=#athleteKey)
SET #username = CONCAT(LOWER(#fname),'.',LOWER(#lname))
SET #email = CONCAT(LOWER(#fname), '.', LOWER(#lname), '#gmail.com')
INSERT INTO [MyDatabase].[dbo].[AspNetUsers]
(Id
,Email
,EmailConfirmed
,[TwoFactorEnabled]
,LockoutEnabled
,AccessFailedCount
,UserName
,FirstName
,LastName)
VALUES
(CAST(#id AS nvarchar(128))
,#email
,#emailconfirmed
,#twofactorenabled
,#lockoutenabled
,#accessFailed
,#username
,#fname
,#lname)
IF #athleteKey % 5 = 0
INSERT INTO [MyDatabase].[dbo].[AspNetUserRoles]
(UserId,RoleId) VALUES (#id, 3)
ELSE
INSERT INTO [MyDatabase].[dbo].[AspNetUserRoles]
(UserId,RoleId) VALUES (#id, 4)
SET #athleteKey = #athleteKey+1
END
You need BEGIN-END in your WHILE loop.
Otherwise it just do not assign value to #id and does not process the loop

Insert update delete trigger

Dear all I´m having trouble with my trigger.
Am I doing this at all right, right now it only works for Insert. I think I´m pretty close tho please help me if you have the time. I´m trying to store all the inserts, updates and deletes into the table customers_changelog via trigger. There is something wrong with the code I cant delete or update customers I can only insert new ones. Please help my I have been spending plenty of hours on this and just cant get this to work! :)
create table customers (
customerid int identity primary key,
name varchar(100) not null,
address varchar(100)
)
go
create table customers_changelog (
customerid int,
name varchar(100) not null,
address varchar(100),
change_user varchar(32),
change_time datetime,
change_action char(1) default 'I',
check (change_action = 'I' or change_action = 'D')
)
go
CREATE TRIGGER log_changes
ON customers
AFTER INSERT, UPDATE, DELETE
AS
BEGIN
SET NOCOUNT ON;
--
-- Check if this is an INSERT, UPDATE or DELETE Action.
--
DECLARE #customerid1 as int;
DEClARE #name1 as varchar(32);
DECLARE #address1 as varchar(100);
DECLARE #change_action1 as char(1);
DECLARE #change_time1 as datetime;
DECLARE #change_user1 as varchar(32);
select #customerid1 = c.customerid, #name1 = c.name, #address1 = c.address
from customers c, inserted i
where c.customerid = i.customerid
SET #change_time1 = CURRENT_TIMESTAMP;
SET #change_user1 = CURRENT_USER;
INSERT INTO customers_changelog(customerid,name,address,change_action,change_time,change_user)
VALUES(#customerid1,#name1,#address1,'I',#change_time1,#change_user1)
IF EXISTS(SELECT * FROM DELETED)
BEGIN
IF EXISTS(SELECT * FROM INSERTED)
INSERT INTO customers_changelog VALUES(#customerid1,#name1,#address1,'U',#change_time1,#change_user1)
ELSE
INSERT INTO customers_changelog VALUES(#customerid1,#name1,#address1,'D',#change_time1,#change_user1)
END
ELSE
IF NOT EXISTS(SELECT * FROM INSERTED) RETURN;
END
Assuming MS-SQL from syntax - So couple issues here:
1. Need to specify column lists in the "update" and "delete" inserts because the column order in the table doesn't match your inserts.
2. Can't use "inserted" data for delete insert
ALTER TRIGGER [dbo].[log_changes] ON [dbo].[customers] AFTER INSERT, UPDATE, DELETE AS
BEGIN
SET NOCOUNT ON;
DECLARE #customerid1 as int;
DEClARE #name1 as varchar(32);
DECLARE #address1 as varchar(100);
DECLARE #change_action1 as char(1);
DECLARE #change_time1 as datetime;
DECLARE #change_user1 as varchar(32);
select #customerid1 = c.customerid, #name1 = c.name, #address1 = c.address
from customers c, inserted i
where c.customerid = i.customerid
SET #change_time1 = CURRENT_TIMESTAMP;
SET #change_user1 = CURRENT_USER;
IF EXISTS(SELECT * FROM DELETED)
BEGIN
IF EXISTS(SELECT * FROM INSERTED)
INSERT INTO customers_changelog(customerid,name,address,change_action,change_time,change_user)
VALUES(#customerid1,#name1,#address1,'U',#change_time1,#change_user1)
ELSE
BEGIN
select #customerid1 = d.customerid, #name1 = d.name, #address1 = d.address
from deleted d
INSERT INTO customers_changelog(customerid,name,address,change_action,change_time,change_user)
VALUES(#customerid1,#name1,#address1,'D',#change_time1,#change_user1)
END
END
ELSE
BEGIN
IF NOT EXISTS(SELECT * FROM INSERTED) RETURN;
INSERT INTO customers_changelog(customerid,name,address,change_action,change_time,change_user)
VALUES(#customerid1,#name1,#address1,'I',#change_time1,#change_user1)
END
END

Resources