Update website when data in SQL Server changes? - sql-server

I am stuck in a problem. There is an application that adds data to database, which is a closed source.
I am creating its web interface. The functionality I want is, that, if a value of some Field in a column is greater than a value in another field in a column, SQL server should http post a message to my site.
Is it possible in Microsoft SQL?
and if yes, How?

Ok, if another software is doing the inserts, you could do it like this...
ALTER TRIGGER [dbo].[ABCD] ON [dbo].[XXX]
FOR INSERT
AS
Declare #A -- from column 1 in INSERT
Declare #B -- from column 2 in INSERT
if (#A > #b)
begin
EXEC msdb.dbo.sp_send_dbmail
#recipients = #email,
#body = #message,
#subject = 'Latest record has column value A greater than column value B'
end
else
begin
--do whatever
end
Ps. sp_send_dbmail is a stored procedure that sends email or messages

Related

Using SQL to send emails based on new entries in tables

I'm looking for a way to send emails (or reminders/confirmations) to users who create a new record in a web application, which is then inserted into a table. Basically a dynamic way of sending emails.
I've been reading online about Triggers and DB mail and there seems to be alot of disadvantages going with this approach.
Does anyone have any recommendations on the best way to achieve this?
Flow: New Record Inserted into DB Table ->>> At this point the email address of the user who created the record in the application should receive a mail (basically a confirmation mail).
What I've tried already:
DB mail is already configured and working.
I've made the below Trigger (very basic) but from reading online using a trigger in this way will lead to load/performance issues of my DB.
But I'm on unsure on how to generate the emails and last record inserted.
CREATE TRIGGER [dbo].[INSERT_Trigger] ON [dbo].[Entity]
FOR INSERT
AS
EXEC msdb.dbo.sp_send_dbmail
#profile_name = 'DBMail',
#recipients = 'admni#domain.com', ####Here I would need dyncamic emails based on what user enters the new record which are stored in the same table
#query = 'Select Description From Entity where 'Last inserted record'####Here I would need the last record for that user entered
#subject = 'Subject' ,
#Body = 'Message Body',
#importance = 'High',
IMHO this approach is a design flaw: the DB tier is something that should be one of the leaves of the tier tree. The fact that the MS SQL Server is actually an application server and has support for such things is a legacy, but I don't think that it should be used.
At first look:
you might need to switch to another RDBMS
your production environment might not support SMTP for any reason
your attempt to send the mail could fail for various reasons - resulting in user not being notified and never trying it again
Yes, indeed, you can use SQL Server even as a message bus but would not be an efficient one. This concept is actually dispatching events of "notification needed" kind. The event is implemented as insert and the trigger is the consumer. But the event is produced inside your application, in a higher tier. Why not reacting to it there? Or, use the database only as a queue: store the details there, but process them in a way where you have more control.
You have not told us about the application you are creating, but I would create a separate background task (the implementation could vary depending on the application design - can be an OS-level scheduled task, windows service, or a background worker in your application) that checks periodically for mails not yet sent, and tries to send them, storing the result in the record. Things might get of course more complicated depending on load. But this way you can retry, and you are certainly taking load of the DB server, but at least you have the possibility to do so.
I have a trigger that works as u asked
First insert records in temporary table from inserted table
Second, declare parameters that you need
Third, add a cursor in your trigger and get parameters that u need in cursor from temporary table
Inside trigger you can declare recipients as u needed to be, query, and other stuffs
CREATE TRIGGER Trigger ON [Entity]
FOR INSERT
not for replication
AS
select ins.* into #temp from inserted ins
declare #Param1 integer, #Param2 integer
declare cursor forward only for
select Col1, Col2 from #temp order by Col1
open cursor
fetch next from cursor into #Param1, #Param2
while ##fetch status = 0
begin
declare #recipients varchar (max), #query varchar(max)
select #recipient = Col1 -- or whatever col contains the recipient address
from #temp
where Col1 = #Param1
select #query = description
from #temp
where Col2 = #Param2 -- or whatever condition give u the description for parameter
exec sp_send_dbmail
#profile_name = 'profile',
#recipients = #recipient
#subject = 'Subject' ,
#Body = #query,
#importance = 'High'
fetch next from cursor into #Param1, #Param2
end
close cursor
deallocate cursor
drop table #temp
--- note that the body can be formatted in html format, like bellow
declare #body varchar(max)
select #body = '<html><body>'
select #body = #body+'Hello'+'<b><b>'
select #body = #body+'Here is the description:'+#query+'<b><b>'
select #body = #body+'Regards'
select #body = #body+'</body></html>'

is there a way i can get an alert whenever a table gets records in sql server

i have a table in SQl server which occasionally gets data from a linked server, and than i have to do activities on it .
but the problem is there is no way to check if the data is inserted in table (table is always truncated after performing the activity so next time when data is pushed table is already empty) i manually check daily for data if it is inserted or not .
what i want is to get auto alert on my email (i already have db_mail configured and working) whenever the data is pushed in a table .
i have sa admin and complete privileges on Database and also on Windows server 2012 R2
You can do this with a trigger but you will have to do some preparations with privileges so the executor (the login that's inserting the records on your tracking table) can send email correctly:
CREATE TRIGGER dbo.TrackingTableNameAfterInsert ON TrackingTable
AFTER INSERT
AS
BEGIN
EXEC msdb.dbo.sp_send_dbmail
#profile_name = 'YourConfiguredProfile',
#recipients = 'youremail#mail.com',
#subject = 'Records were inserted on TrackingTable',
#body = ''
END
You might want to encapsulate the email sending on an SP and configure it's permissions there.
In regards to the following:
...table is always truncated after performing the activity so next time
when data is pushed table is already empty...
You can create a historical table and use a trigger to also insert inserted records on this table, so the TRUNCATE or DROP of the original one won't affect the copied records.
CREATE TABLE TrackingTableMirror (
/*Same columns and types*/
InsertedDate DATETIME DEFAULT GETDATE())
GO
CREATE TRIGGER dbo.TrackingTableInsertMirror ON TrackingTable
AFTER INSERT
AS
BEGIN
INSERT INTO TrackingTableMirror (
/*Column list*/)
SELECT
/*Column list*/
FROM
inserted AS I
END
This way you can check all records on this mirrored table and not the volatile one (and avoid all the email sending).
1) Create Profile and Account
You need to create a profile and account using the Configure Database Mail Wizard which can be accessed from the Configure Database Mail context menu of the Database Mail node in Management Node. This wizard is used to manage accounts, profiles, and Database Mail global settings.
2) Run Query
sp_CONFIGURE 'show advanced', 1
GO
RECONFIGURE
GO
sp_CONFIGURE 'Database Mail XPs', 1
GO
RECONFIGURE
GO
3)
USE msdb
GO
EXEC sp_send_dbmail #profile_name='yourprofilename',
#recipients='test#Example.com',
#subject='Test message',
#body='This is the body of the test message.
Congrates Database Mail Received By you Successfully.'
through the table
DECLARE #email_id NVARCHAR(450), #id BIGINT, #max_id BIGINT, #query NVARCHAR(1000)
SELECT #id=MIN(id), #max_id=MAX(id) FROM [email_adresses]
WHILE #id<=#max_id
BEGIN
SELECT #email_id=email_id
FROM [email_adresses]
set #query='sp_send_dbmail #profile_name=''yourprofilename'',
#recipients='''+#email_id+''',
#subject=''Test message'',
#body=''This is the body of the test message.
Congrates Database Mail Received By you Successfully.'''
EXEC #query
SELECT #id=MIN(id) FROM [email_adresses] where id>#id
END
4) Trigger Code
CREATE TRIGGER [dbo].[Customer_INSERT_Notification]
ON [dbo].[Customers]
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
DECLARE #CustomerId INT
SELECT #CustomerId = INSERTED.CustomerId
FROM INSERTED
declare #body varchar(500) = 'Customer with ID: ' + CAST(#CustomerId AS VARCHAR(5)) + ' inserted.'
EXEC msdb.dbo.sp_send_dbmail
#profile_name = 'Email_Profile'
,#recipients = 'recipient#gmail.com'
,#subject = 'New Customer Record'
,#body = #body
,#importance ='HIGH'
END
I refer this link.

SQL Server 2008 Trigger which sends email

Does anyone know why this wouldn't work? It's a trigger which checks the value of a field on insert and update and sends an email with the value of an id column from the offending row.
ALTER TRIGGER [dbo].[DB]
ON [dbo].[table]
AFTER INSERT, UPDATE AS
BEGIN
IF EXISTS(SELECT 1 FROM inserted WHERE value = 5)
BEGIN
EXEC msdb.dbo.sp_send_dbmail
#recipients = 'me#derp.com',
#profile_name = 'MailProfile',
#subject = 'DB.dbo.table trigger',
#body = '',
#execute_query_database = 'DB',
#query = 'USE DB SET NOCOUNT ON SELECT id FROM dbo.table WHERE value = 5';
END
END
The problem seems to be the #query in the sp_send_dbmail function. When I manually try triggering it I receive the following error;
No row was updated.
The data in row x was not committed.
Error Source: .Net SqlClient Data Provider.
Error Message: Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding.
Correct the errors and retry or press ESC to cancel the change(s).
When I remove #execute_query_database and #query and add some plain text to the #body var the trigger works and I receive an email.
I've also tried changing the #query value to something really simple e.g. SELECT "Test" as test but this didn't help.
I'm completely new to triggers so if the problem is painfully obvious... apologies :)
You need semi-colons:
#query = 'USE DB; SET NOCOUNT ON; SELECT id FROM dbo.table WHERE value = 5;';

Stored Procedure Does Not Fire Last Command

On our SQL Server (Version 10.0.1600), I have a stored procedure that I wrote.
It is not throwing any errors, and it is returning the correct values after making the insert in the database.
However, the last command spSendEventNotificationEmail (which sends out email notifications) is not being run.
I can run the spSendEventNotificationEmail script manually using the same data, and the notifications show up, so I know it works.
Is there something wrong with how I call it in my stored procedure?
[dbo].[spUpdateRequest](#packetID int, #statusID int output, #empID int, #mtf nVarChar(50)) AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE #id int
SET #id=-1
-- Insert statements for procedure here
SELECT A.ID, PacketID, StatusID
INTO #act FROM Action A JOIN Request R ON (R.ID=A.RequestID)
WHERE (PacketID=#packetID) AND (StatusID=#statusID)
IF ((SELECT COUNT(ID) FROM #act)=0) BEGIN -- this statusID has not been entered. Continue
SELECT ID, MTF
INTO #req FROM Request
WHERE PacketID=#packetID
WHILE (0 < (SELECT COUNT(ID) FROM #req)) BEGIN
SELECT TOP 1 #id=ID FROM #req
INSERT INTO Action (RequestID, StatusID, EmpID, DateStamp)
VALUES (#id, #statusID, #empID, GETDATE())
IF ((#mtf IS NOT NULL) AND (0 < LEN(RTRIM(#mtf)))) BEGIN
UPDATE Request SET MTF=#mtf WHERE ID=#id
END
DELETE #req WHERE ID=#id
END
DROP TABLE #req
SELECT #id=##IDENTITY, #statusID=StatusID FROM Action
SELECT TOP 1 #statusID=ID FROM Status
WHERE (#statusID<ID) AND (-1 < Sequence)
EXEC spSendEventNotificationEmail #packetID, #statusID, 'http:\\cpweb:8100\NextStep.aspx'
END ELSE BEGIN
SET #statusID = -1
END
DROP TABLE #act
END
Idea of how the data tables are connected:
From your comments I get you do mainly C# development. A basic test is to make sure the sproc is called with the exact same arguments you expect
PRINT '#packetID: ' + #packetID
PRINT '#statusID: ' + #statusID
EXEC spSendEventNotificationEmail #packetID, #statusID, 'http:\\cpweb:8100\NextStep.aspx'
This way you 1. know that the exec statement is reached 2. the exact values
If this all works than I very good candidate is that you have permission to run the sproc and your (C#?) code that calls it doesn't. I would expect that an error is thrown tough.
A quick test to see if the EXEC is executed fine is to do an insert in a dummy table after it.
Update 1
I suggested to add PRINT statements but indeed as you say you cannot (easily) catch them from C#. What you could do is insert the 2 variables in a log table that you newly create. This way you know the exact values that flow from the C# execution.
As to the why it now works if you add permissions I can't give you a ready answer. SQL security is not transparent to me either. But its good to research yourself a but further. Do you have to add both guest and public?
It would also help to see what's going inside spSendEventNotificationEmail. Chances are good that sproc is using a resource where it didn't have permission before. This could be an object like a table or maybe another sproc. Security is heavily dependent on context/settings and not an easy problem to tackle with a Q/A site like SO.

sp_send_dbmail is not working

I am trying (unsuccessfully) to use sp_send_dbmail (Transact-SQL).
The #recipients value is said to be a semicolon-delimited list of e-mail addresses to send the message to.
So, in my data table's Email column, all I should have to do is update the row to send to multiple recipients:
Old: JoeP#jp2code.net
New: JoeP#jp2code.net; personB#jp2code.net
There are no errors, but then there is no email going out.
The code I use to call sp_send_dbmail is unchanged in my stored procedure:
IF (0 < (SELECT COUNT(ID) FROM #Email)) BEGIN
SELECT TOP 1 #ID=ID, #email=Email FROM #Email
EXEC msdb.dbo.sp_send_dbmail #recipients=#email, #subject=#subj, #body=#html, #body_format='HTML', #from_address='no-reply#jp2code.net', #reply_to=#email;
DELETE #Email WHERE #email=Email
END
So, what is wrong?
I may have found the issue...
#reply_to=#email;
[ #reply_to= ] 'reply_to'
Is the value of the 'reply to address' of the email message. It accepts only one email address as a valid value. This is an optional parameter used to override the settings in the mail profile. This parameter is of type varchar(MAX). SMTP secuirty settings determine if these overrides are accepted. If no parameter is specified, the default is NULL.
This explains why it worked with a single address, but doesn't work with multiple addresses.
Stupid mistake.
Take a closer look at the SQL:
IF (0 < (SELECT COUNT(ID) FROM #Email)) BEGIN
SELECT TOP 1 #ID=ID, #email=Email FROM #Email
EXEC msdb.dbo.sp_send_dbmail
#recipients=#email,
#subject=#subj,
#body=#html,
#body_format='HTML',
#from_address='no-reply#jp2code.net',
#reply_to=#email;
DELETE #Email WHERE #email=Email
END
Does everyone see the problem now?
Hint: Look at the reply_to field.

Resources