New row alert via email [duplicate] - sql

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

Stored Procedure - Table Name as variable

I am tasked with writing a stored procedure that will validate the input data against a few tables before inserting into a main table named CHANGES.
Here is what I am dealing with table wise:
There is a lookup table. This table basically gives the user the rules of data validation before it can be inserted into the MAIN table. The lookup table looks like this:
ID TABLECODE COLUMNAME ACCEPTEDDATATYPE
1 luDEPT DEPTCODE INT
2 luEMP GENDERCODE INT
3 luDEPT BLDGcode INT
So if a user is inserting an ID of 1, we know they are trying to make a correction to the DeptCode column and they must meet the requirements that only an Integer will be accepted before inserting into the CHANGES table (this is the main table that will hold the new values).
CHANGES table - Data is inserted into this table with the new value per column. Data will only be inserted into this table if it passes validation against the lookup table and explained in part 3.
Structure of CHANGES table
ID pkid NEWVALUE
1 67 01
1 84 09
2 56 03
This is the part I would like some help/input with to even see if it's doable. The column from the LOOKUP table name TABLECODE is the name of an actual table that exists in the database with codes and description for each column. So for example, all the DEPTCODE codes will be found in a lookup table named: luDEPT
Here is how the luDEPT that looks like this:
CODE DEPARTMENTNAME
01 BIOLOGY
02 CHEMISTRY
03 INFORMATION TECHNOLOGY
So another validation step I have to take is, make sure that the NEW VALUE being inserted into CHANGES table is a valid code found in the lookup table related to the COLUMNNAME.
This is what I have so far, which works
CREATE PROCEDURE [dbo].[NewValueData]
(
#ID int,
#pkid VARCHAR(40),
#value VARCHAR(50)
)
AS
Begin
declare #result bit = 0;
declare #result1 bit = 0;
declare #result2 bit = 0;
declare #result3 bit = 0;
declare #result4 bit = 0;
DECLARE #tablename varchar(50);
DECLARE #columndatatype varchar(30);
set #columndatatype=(select accepteddatatype from lookup where ID=#ID)
**set #tablename=(select TABLE_NAME from INFORMATION_SCHEMA.TABLES A, lookup b
where a.TABLE_NAME= b.lutablecode
and TABLE_SCHEMA = 'Test' and ID=#ID)**
--CHECK IF ID, pkid and VALUE are PROVIDED
if (#pkid IS NULL OR #pkid = '') or (#ID IS NULL OR #ID = '') or (#value IS NULL OR #value =
'')
begin
set #result = 1
PRINT 'PKID,ID or Value is missing'
end
--CHECK IF ID EXISTS IN LOOKUP TABLE
if #ID not in (select ID from lookup
where #ID=ID)
begin
set #result1=1
PRINT 'ID is not in lookup table'
end
--IF datatype is an integer, only accept a numeric value
if #columndatatype = 'INT'
begin
set #result3 = IIF(ISNUMERIC(#value)=1,0,1)
PRINT 'column type is INT '
end
**--ATTEMPT of trying to use #tablename
--CHECK IF VALUE IS AN ACCEPTED VALUE IN THE LOOKUP TABLE FOR THAT COLUMN
if #value not in (select code from #tablename where #value=code)
begin
set #result4=1
PRINT 'Not a valid code')
end**
if (#result = 0 and #result1 = 0 and #result2 = 0 and #result3 = 0 and #result4 = 0)
begin
BEGIN TRANSACTION;
begin try
INSERT INTO [CHANGES] (ID, pkid,newvalue) VALUES (#ID, #pkid, #value)
PRINT 'New Record Inserted'
COMMIT TRANSACTION
end TRY
begin catch
ROLLBACK TRANSACTION
PRINT 'id is not acceptable'
END
end
GO
The text in bold is my attempt at trying to derive the tablename dynamically but it doesn't work. Does anyone have suggestion on how to go about this issue? Any help will be welcomed.
Try something like:
DECLARE #tablename sysname = 'luDEPT'
DECLARE #columnname sysname = 'DEPTCODE'
DECLARE #value INT = 123
DECLARE #valid BIT
DECLARE #sql NVARCHAR(MAX) = '
SET #Valid = CASE
WHEN EXISTS(SELECT * FROM ' + QUOTENAME(#tablename) + ' WHERE ' + QUOTENAME(#columnname) + ' = #Value)
THEN 1
ELSE 0
END'
EXECUTE sp_executesql
#sql,
N'#value INT, #valid BIT OUTPUT',
#value = #value, #valid = #valid OUTPUT
SELECT Valid = #Valid
The data type could potentially also be parameterized if types other than INT are needed.

Using while exists in triggers sends the query in infinite loop

I created a trigger for insert and it works fine. This creates the trigger just fine:
While (exists(Select Id from #temp))
But the insert query is going into an infinite loop. I am using while exists to accommodate multiple insertions at a time. Can anyone tell me what is causing the infinite loop?
Create Table sqltutorial.Employee
(
Id int,
Name nvarchar(50),
Salary int,
Gender nvarchar(50),
DepartmentId int
)
Alter Trigger sqltutorial.trg_forinsert_Employee
on sqltutorial.Employee
For Insert
As
Begin
print 'Audit Begins'
Declare #Id int, #Name nvarchar(50), #Salary int,
#Gender nvarchar(50), #DepartmentId nvarchar(50)
Declare #AuditText nvarchar(500)
Select *
into #temp
from inserted
While (exists(Select Id from #temp))
Select #Id = Id from #temp
Select
#Id = Id, #Name = Name, #Salary = Salary,
#Gender = Gender, #DepartmentId = DepartmentID
from
#temp
Set #AuditText = 'New Record Inserted With Id='+Cast(#Id As nvarchar(50))+',Name='+#Name+' ,Salary='+CAST(#Salary as nvarchar(50))+' Gender'+#Gender
+' ,Department Id='+#DepartmentId+' on '+CAST((Select GETDATE()) AS nvarchar(50))+' by '+(Select system_user)
Insert into sqltutorial.AuditTrial
values (#AuditText)
Delete from #temp
where Id = #Id
print 'Audit Ends'
End
The reason for the infinite loop is that you did not specify a BEGIN and END to your WHILE loop code block like this:
WHILE SomeCondition = true
BEGIN
Do stuff
END
When you use WHILE and don't specify BEGIN..END, the WHILE loop repeats the next statement only, over and over until the WHILE condition is no longer met. And in your code, that would never happen, since the next statement doesn't delete anything from #temp.
In other words, in your code, this is what you are looping:
While (exists(Select Id from #temp))
Select #Id = Id from #temp
The rest of the code after this never even executes because the WHILE loop never exits.
You don't need to use all the variables and temp tables in your trigger simply do the following:
ALTER TRIGGER sqltutorial.trg_forinsert_Employee
ON sqltutorial.Employee
FOR INSERT
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO sqltutorial.AuditTrial
SELECT
' New Record Inserted With Id=' + CAST([Id] AS NVARCHAR(50)) +
',Name=' + [Name] +
',Salary=' + CAST(Salary AS NVARCHAR(50)) +
',Gender' + Gender +
',Department Id=' + DepartmentId +
' on ' + CAST((SELECT GETDATE()) AS NVARCHAR(50)) +
' by ' + CAST(system_user AS NVARCHAR(256))
FROM
inserted
END

SQL Server stored procedure: verify CRUD operation success/failure using output variable

I am trying to create a SQL Server stored procedure to handle updates to a table using some dynamic SQL. The table name required for the update is stored in a table that correlates a table id to a category id. Once the table name is retrieved and the table id is not null, I update the table using a dynamic SQL query as shown below:
CREATE PROCEDURE [dbo].[SP_EBS_CustomForms_SetCategoryData]
(#flag int output,
#cat_id int,
#sort int,
#value varchar(50),
#active int,
#enum int)
AS
BEGIN
DECLARE #tbl as varchar(50)
DECLARE #tbl_id as int
DECLARE #sql nvarchar(max)
BEGIN TRY
SET #tbl_id = (SELECT [tbl_id]
FROM [demodata].[dbo].[ebscustomforms_cattable]
WHERE cat_id = #cat_id)
IF #tbl_id IS NOT NULL
BEGIN
SET #tbl = (SELECT table_name
FROM ebscustomforms_enumtable
WHERE tbl_id = #tbl_id)
SET #sql = 'UPDATE ' + #tbl + ' SET [sort_order] = #sort, [value] = #value, [active] = #active WHERE [enum_id] = #enum'
EXECUTE sp_executesql #sql, N'#sort int, #value varchar(50), #active int, #enum int', #sort, #value, #active, #enum
SET #flag = 0
RETURN #flag
END
END TRY
BEGIN CATCH
IF ##ERROR <> 0
BEGIN
SET #flag = 1;
RETURN #flag
END
END CATCH
END
I want this stored procedure to return an int value indicating whether the stored procedure was successful (0) or failed (1) updating the table.
Points of error are as follows:
#tbl_id variable is null
#tbl is either null or an empty varchar
The table to be updated does not have a record where [enum_id] = #enum
I have noticed that when I try to update a record that does not exist, the procedure seems to return as successful i.e. #flag = 0. However, I would imagine that an error should be thrown because the record does not exist.

Creating an Instead of insert Trigger SQL

I am a DBA with my company. I am trying to create trigger that will check any insert statement for duplicates first then if none allow the original insert. Not even sure this can be done. The insert statements may be written by various users so the statements will never be the same. All I have found so far is the check for duplicates but the insert statement is then hard coded in the trigger. My plan is also to check update as well, but it is not important right now.
Here is my current code.
ALTER TRIGGER [dbo].[BlockDuplicatesOnTable]
ON [dbo].[blockduplicates]
Instead of INSERT, Update
AS
BEGIN
SET NOCOUNT ON;
Declare #ProviderAcctNumber nvarchar(50)
Declare #Referredby int
Declare #Action as char(1)
Declare #Count as int
Set #Action = 'I'
Select #Count = Count(*) from DELETED
IF #Count > 0
Begin
Set #Action = 'D'
Select #Count = count(*) from INSERTED
IF #Count > 0
Set #Action = 'U'
IF #Action = 'I'
Begin
IF not exists (Select 1 from inserted as i
inner join dbo.blockduplicates as b
on i.ProviderAcctNumber = b.ProviderAcctNumber
and i.Referredby = b.Referredby)
Begin
--execute original insert
End
Else
Begin
Print 'Duplicate insert'
Raiserror ('Duplicate Entry for Insert',16,1);
Return
End
End
Else IF #Action = 'U'
Begin
Select #ProviderAcctNumber = ProviderAcctNumber, #Referredby = Referredby from inserted
IF Not exists (Select 1 from deleted where ProviderAcctNumber = #ProviderAcctNumber and Referredby = #Referredby)
Begin
Print 'Update Statement is True';
End
Else
Begin
Print 'duplicate'
Raiserror ('Duplicate Entry for Update',16,1);
Return
End
End
End
End;

Stored Procedure OutPut Parameters

i need to write a stored procedure which will return a string.logic is
when user try to insert a new record i need to check whether that record already exist.if exist need to return msg "Record exist" else return "Inserted"
following is what i have done for the moment and i'm stuck here.can some one help me to complete the procedure
CREATE PROCEDURE [dbo].[spInsetPurpose]
#Purpose VARCHAR(500),
#Type VARCHAR(6),
#Result VARCHAR(10)= NULL OUTPUT
AS
BEGIN
Declare #Position VARCHAR(20)
DECLARE #TempTable TABLE (Purpose VARCHAR(500))
INSERT INTO #TempTable
SELECT Purpose FROM tblPurpose WHERE Purpose=#Purpose
INSERT INTO tblPurpose(Purpose,[Type]) VALUES(#Purpose,#Type)
END
To check if the row already exists you can do
If Exists (Select Top 1 1 from tblPurpose where Purpose = #Purpose and [Type] = #Type)
Begin
Insert Into tblPurpose
(Purpose, [Type])
Select
#Purpose, #Type
SET #Result = 'Inserted'
End
Else
Begin
SET #Result = 'Record exists'
End