loneieagle2
asked on
AFTER UPDATE TRIGGER is causing the save operation to fail.
I am trying to set up a trigger to send an Email when a field is updated. I did it very simply just to test my Email setup. The trigger works if I make the change in the record, but if another employee makes the change, they get an error that a save operation on Mytable failed. If I disable the trigger the second employee is able to make the change with no problem. Where can I look to see why it is failing? The SQL agent logs show nothing happening at this time.
This is SQL 2016.
Here is my trigger:
CREATE TRIGGER [dbo].[Change_Patient]
ON [dbo].[mytable]
AFTER UPDATE
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
declare @OldAddress varchar(50)
declare @NewAddress varchar(50)
declare @Email varchar(500)
declare @EBody varchar(max)
select @OldAddress = DELETED.Street_Name from deleted
select @NewAddress = inserted.Street_Name from inserted
--select @OldAddress='OLD'
--select @NewAddress='New'
select @Email = 'emp1@mycompany.com; emp2@mycompany.com'
select @Ebody = 'The field Address was changed from ' + @OldAddress + ' to ' + @NewAddress
EXEC msdb.dbo.sp_send_dbmail @profile_name= 'SQL Mail Profile',
@recipients = @Email,
@subject = 'Testing Trigger',
@body=@Ebody
END
GO
This is SQL 2016.
Here is my trigger:
CREATE TRIGGER [dbo].[Change_Patient]
ON [dbo].[mytable]
AFTER UPDATE
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
declare @OldAddress varchar(50)
declare @NewAddress varchar(50)
declare @Email varchar(500)
declare @EBody varchar(max)
select @OldAddress = DELETED.Street_Name from deleted
select @NewAddress = inserted.Street_Name from inserted
--select @OldAddress='OLD'
--select @NewAddress='New'
select @Email = 'emp1@mycompany.com; emp2@mycompany.com'
select @Ebody = 'The field Address was changed from ' + @OldAddress + ' to ' + @NewAddress
EXEC msdb.dbo.sp_send_dbmail @profile_name= 'SQL Mail Profile',
@recipients = @Email,
@subject = 'Testing Trigger',
@body=@Ebody
END
GO
ASKER CERTIFIED SOLUTION
membership
Create a free account to see this answer
Signing up is free and takes 30 seconds. No credit card required.
I'm not a SQL Server Expert. I'm going from other systems that when one person can execute a procedure and another cannot, it is almost always permissions.
If I look at:
https://docs.microsoft.com/en-us/sql/t-sql/statements/execute-as-clause-transact-sql?view=sql-server-2017
The default is CALLER. Seems to point to the other user not being able to execute sp_send_dbmail where you can.
Looks like there is a DatabaseMailUserRole:
https://docs.microsoft.com/en-us/previous-versions/sql/sql-server-2008-r2/ms188719(v=sql.105)
If I look at:
https://docs.microsoft.com/en-us/sql/t-sql/statements/execute-as-clause-transact-sql?view=sql-server-2017
The default is CALLER. Seems to point to the other user not being able to execute sp_send_dbmail where you can.
Looks like there is a DatabaseMailUserRole:
https://docs.microsoft.com/en-us/previous-versions/sql/sql-server-2008-r2/ms188719(v=sql.105)
>> I did it very simply just to test my Email setup
What is the Authentication you have used for Database Mail configuration..
Kindly check whether the other login have access to send mail or else have Execute rights on msdb.dbo.sp_send_dbmail procedure..
If not, then just grant execute rights on the above procedure to get it work..
What is the Authentication you have used for Database Mail configuration..
Kindly check whether the other login have access to send mail or else have Execute rights on msdb.dbo.sp_send_dbmail procedure..
If not, then just grant execute rights on the above procedure to get it work..
Hi,
often developers are set as sysadmin permission, in that case you have full access to anything including the sendmail function which is not in your database but in the msdb database where normal users have no access to.
To use this function one way to go is to open your database and the msdb database as trusted databases but this also opens other security holes. I prefer to use a stored procedure as wrapper procedure on the own database where also the parameters can be controlled and then use a certificate to sign the SP which can then use the msdb SP to send the mail.
Another issue with your trigger is that you missed to write it in a way to handle more than one record. The UPDATE trigger (all triggers) are called once for one operation, if that contains more than one record it will not call the trigger again. For that purpose the "inserted" and "deleted" tables given to the trigger contains all affected records and all triggers need to be programmed that they use that. If you assign a variable like you do you can never be sure which record you got as it doesn't contain a WHERE clause or anything else to specify the desired record. You would also need a loop to execute the sendmail for each record.
Cheers,
Christian
often developers are set as sysadmin permission, in that case you have full access to anything including the sendmail function which is not in your database but in the msdb database where normal users have no access to.
To use this function one way to go is to open your database and the msdb database as trusted databases but this also opens other security holes. I prefer to use a stored procedure as wrapper procedure on the own database where also the parameters can be controlled and then use a certificate to sign the SP which can then use the msdb SP to send the mail.
Another issue with your trigger is that you missed to write it in a way to handle more than one record. The UPDATE trigger (all triggers) are called once for one operation, if that contains more than one record it will not call the trigger again. For that purpose the "inserted" and "deleted" tables given to the trigger contains all affected records and all triggers need to be programmed that they use that. If you assign a variable like you do you can never be sure which record you got as it doesn't contain a WHERE clause or anything else to specify the desired record. You would also need a loop to execute the sendmail for each record.
Cheers,
Christian
ASKER
I won't have time to test this for a while, but I think you've nailed my issue. Bitsqueezer, thanks for your input, I knew about having to loop through records. I think only one at a time will be updated, but the final version will allow for more than one.
One final question. If there is an error like this in my trigger it stops the original update, which I want to avoid. Will this work,
Have the trigger call a stored procedure.
In the procedure use a TRY ... CATCH to trap any errors.
Either way return a no error code to the trigger.
Thanks
One final question. If there is an error like this in my trigger it stops the original update, which I want to avoid. Will this work,
Have the trigger call a stored procedure.
In the procedure use a TRY ... CATCH to trap any errors.
Either way return a no error code to the trigger.
Thanks
Hi,
a TRY/CATCH construct is also possible in the trigger code itself, you do not need to write a SP for that.
You could use that to write the error code and other error variables into an error table which maybe gives you the information why it fails in case of the other users so you could remove the source of the error.
Cheers,
Christian
a TRY/CATCH construct is also possible in the trigger code itself, you do not need to write a SP for that.
You could use that to write the error code and other error variables into an error table which maybe gives you the information why it fails in case of the other users so you could remove the source of the error.
Cheers,
Christian
ASKER