Using sp_send_dbmail with recieptent and content from single sql row - sql

I have a table filled with oldUserID, newUserID, name and email. I want to use sp_send_dbmail to the email on each row. For example:
oldUserID | newUserID | name | email
21213125 | 2355233571 | Tom | tom#gmail.com
65465465 | 4564884664 | Mat | mat#gmail.com
And so on for 200 rows. Is there any way to send an sp_send_dbmail to the email on each row including oldUserID and newUserID? The output in the mail would be something like:
"Your old user id: 21213125, your new user id: 2355233571"
I would appreciate not to enter each emailadress manually.
Thank you!

DECLARE
#txt NVARCHAR(MAX)
, #name NVARCHAR(60)
, #email VARCHAR(100)
DECLARE cur CURSOR FAST_FORWARD READ_ONLY LOCAL FOR
SELECT 'Your old user id: ' + CAST(oldUserID AS NVARCHAR(100))
+ ', your new user id: ' + CAST(newUserID AS NVARCHAR(100)), name, email
FROM ...
OPEN cur
FETCH NEXT FROM cur INTO #txt, #name, #email
WHILE ##fetch_status = 0
BEGIN
EXEC msdb.dbo.sp_send_dbmail #profile_name = ...
, #recipients = #email
, #subject = #name
, #body = #txt
, #body_format = 'HTML'
FETCH NEXT FROM cur INTO #txt, #name, #email
END
CLOSE cur
DEALLOCATE cur

Related

SQL Cursor and Email

I have a cursor in place that needs to send an email to one person containing all the rows associated with a certain field
To explain a bit further, i have a table which contains multiple rows, with one field containing the email address for all the rows associated with that email address.
I'm looking to send one email for that user with all the rows associated with that email address. At the moment, so if it has 4 rows, sends one email with all those rows. What its doing at the moment is sending 4 emails with all the rows associated with that email address
Essentially, just need it to send one email with all the rows for that email address
Thanks
Cursor loops through
Updates a table
Email then uses the variables to send the email
DECLARE #SUBJECT VARCHAR(100)
DECLARE #BODY VARCHAR(MAX)
DECLARE #EMAIL VARCHAR(60)
DECLARE #SUPERVISOREMAIL VARCHAR(60)
DECLARE #TABLEHTML VARCHAR(MAX)
DECLARE #TPROFILE VARCHAR(128)
DECLARE #ASSETREF VARCHAR(MAX)
DECLARE #PERSONREF VARCHAR(MAX)
DECLARE #USERNAME VARCHAR(MAX)
DECLARE #UPDATEDINVFIRE BIT
DECLARE #DATEUPDATEDINVFIRE DATETIME
DECLARE #DEVICEMODEL VARCHAR(MAX)
DECLARE #DESCRIPTION VARCHAR(MAX)
DECLARE CSR CURSOR
FOR SELECT ASSETREF, USERNAME, EMAIL, SUPERVISOREMAIL, UPDATEDINVFIRE, DATEUPDATEDINVFIRE FROM ##LEAVERUPDATE
OPEN CSR FETCH NEXT
FROM CSR INTO #ASSETREF, #USERNAME, #EMAIL, #SUPERVISOREMAIL, #UPDATEDINVFIRE, #DATEUPDATEDINVFIRE
WHILE ##FETCH_STATUS = 0
BEGIN
SET #SUBJECT = 'VFIRE DEVICE STATUS UPDATED FOR LEAVER'
SET #TABLEHTML = N'<P> The following user has had the following devices set to leaver status in vFire</P>' +
N'<P> Please be advised, these devices need to be returned immediately prior to the person leaving the business</P>' +
N'<table border="1">' +
N'<tr><th>CI Number</th><th>Username</th><th>Asset Model</th><th>Asset Description</th><th>Users Email Address</th><th>Supervisor EMail Address</th></tr>' +
CAST
((
SELECT
TD = ASSETREF, '',
TD = USERNAME, '',
TD = DEVICEMODEL, '',
TD = DESCRIPTION,'',
TD = EMAIL, '',
TD = SUPERVISOREMAIL,''
FROM ##LEAVERUPDATE
WHERE EMAIL = #EMAIL
FOR XML PATH('TR'), TYPE
) AS NVARCHAR(MAX) ) +
N'</TABLE>' +
N'<P> </P>';
EXEC msdb.dbo.sp_send_dbmail
#profile_name = #TPROFILE,
#recipients = #SUPERVISOREMAIL,
#copy_recipients='',
#blind_copy_recipients ='',
#subject = #SUBJECT,
#body = #TABLEHTML,
#body_format = 'HTML'
------------------------------------------
FETCH NEXT
FROM CSR INTO #ASSETREF, #USERNAME, #EMAIL, #SUPERVISOREMAIL, #UPDATEDINVFIRE, #DATEUPDATEDINVFIRE
END
CLOSE CSR
DEALLOCATE CSR

Select into is selecting last record when trying to generate dynamic update statement for each table

I have a table like below :
Archival:
TableName ColumnName Datatype NewValue
Employee FirstName nvarchar Abc
Employee LastName nvarchar Pqr
Employee Age int 28
Address City nvarchar Chicago
Address StreetName nvarchar KKKKK
I am trying to create dynamic update statement for each table and want to execute update statement for each individual table and rollback if any update fails.
Expected update statement query for each individual table:
Update Employee set FirstName = 'Abc', LastName = 'Pqr', Age = 21
where DepartmentId = 100;
Update Address set City = 'Chicago', StreetName = 'KKKKK'
where DepartmentId = 100;
Stored Procedure:
Alter PROC [dbo].[UpdateDataByDeptID]
#departmentId int
As
Begin
Declare db_cursor CURSOR for select TableName from Archival
group by TableName
Declare #tableName nvarchar(50),
#columnName nvarchar(50),
#datatype nvarchar(50),
#newValue nvarchar(50)
open db_cursor
Fetch Next from db_cursor into #tableName;
While ##FETCH_STATUS = 0
Begin
select #columnName = ColumnName,
#datatype = Datatype,
#newValue = NewValue
from Archival where TableName = #tableName;
print #tableName + ' ' + #columnName + ' ' + #newValue
Fetch Next from db_cursor into #tableName
End;
close db_cursor;
DEALLOCATE db_cursor;
Begin Transaction
Begin Try
--execute each of the update statement like below for ex:
Update Employee .....
Update Address .....
Commit transaction
End Try
Begin Catch
Rollback
End Catch
End
End -- end of SP
But the problem is this line :
print #tableName + ' ' + #columnName + ' ' + #newValue
Above line is giving me last record for each table. For example for Employee table :
Employee Age int 28
Hence I am not able to generate individual update statement for each table.
Final expected output is below for my transaction after each update statement for each individual table:
Begin Transaction
Begin Try
--execute each of the update statement like below for ex:
Update Employee set FirstName = 'Abc', LastName = 'Pqr', Age = 21
where DepartmentId = 100;
Update Address set City = 'Chicago', StreetName = 'KKKKK'
where DepartmentId = 100;
Commit transaction
End Try
Begin Catch
Rollback
End Catch
End
Can someone please help me with this?
An example of how you could approach something like this is by using dynamic SQL.
For example:
DECLARE #sql NVARCHAR(MAX) = N'';
DECLARE #tablename NVARCHAR(255);
DECLARE db_cursor CURSOR FOR
SELECT DISTINCT [TableName] FROM [Archival];
OPEN db_cursor;
FETCH NEXT FROM db_cursor INTO #tablename;
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #sql += N'UPDATE ' + QUOTENAME(#tablename) + ' SET ';
SELECT #sql += QUOTENAME([ColumnName]) + N' = ' + QUOTENAME([NewValue], '''') + N', '
FROM [Archival]
WHERE [TableName] = #tablename;
SELECT #sql = SUBSTRING(#sql, 1, LEN(#sql) - 1) + N'
WHERE DepartmentId = 100;
';
FETCH NEXT FROM db_cursor INTO #tablename;
END
CLOSE db_cursor;
DEALLOCATE db_cursor;
PRINT #sql;
-- EXEC sp_executesql #sql;
Which should give you something to your expected output, I believe.
I would be careful when doing something like this though if you can't trust what's in the NewValue column. (e.g. if it's possible for someone to put in some sort of malicious SQL that would be executed here).

How to send an email only to users who appear in query results?

I am creating a query to return tickets that haven't been updated in the required time and send via email. I have everything working except I want to email only the users whose names appear in the query results.
I have tried setting the # user name = to user id and adding to the email as below. Not sure if this is even close.
Declare #username VARCHAR(MAX)
--("query")--
Set #username =[userid]--(in query results)--
exec msdb.dbo.sp_send_dbmail
#participants ='#username+#mydomain.com'
Expect to send emails to users whose user name appears in query results.
You can use STUFF with FOR XML PATH to create a ; delimited list for the #recipients parameter:
DECLARE #EmailList varchar(max)
SELECT #EmailList = STUFF((
SELECT ';' + Username + '#gmail.com'
FROM yourTable
FOR XML PATH('')
), 1, 1, '')
Then:
EXEC msdb.dbo.sp_send_dbmail
#recipients = #EmailList,
#subject = 'foo',
#body = 'bar',
etc
You can use Coalesce to create a list separated with semicolons which is what dbmail wants.
Declare #username varchar(max)
SELECT
#username = COALESCE(#username + '; ','') + userid + '#mydomain'
FROM
Yourtable
WHERE
Yourquery
EXEC msdb.dbo.sp_send_dbmail
#recipients = #username
#subject = 'BARK BARK'
#Body = 'BARK BARK BARK'
You can use a CURSOR to fetch your email address list and send the email to that list:
DECLARE #username AS VARCHAR(MAX) = ''
DECLARE #participants AS VARCHAR(MAX) = ''
DECLARE cursor_name CURSOR
FOR
SELECT userid
FROM YourTable
OPEN cursor_name;
FETCH NEXT
FROM cursor_name
INTO #username;
WHILE ##FETCH_STATUS = 0
BEGIN
#participants += #username + '#mydomain.com;'
FETCH NEXT FROM cursor_name
INTO #username;
END
CLOSE cursor_name;
DEALLOCATE cursor_name;
EXEC msdb.dbo.sp_send_dbmail #recipients = #participants
etc

SQL send db mail to multiple recipients with each related data

I've created a two stored procedures, one holding the data info and the other is more for the call of db mail. I have a samples of the second stored procedure below as the issues is there.
BEGIN
SET NOCOUNT ON;
declare #Coord_ID varchar(20)
declare #Coord_Name varchar(25)
declare #Coord_Email varchar(75)
declare #CoordCursor as cursor
declare #tab char(1) = CHAR(9)
declare #emailBody varchar(100)
declare #sqlCommand varchar(1000) = 'sp_MZ_Get'
declare #qry varchar(1000)
set #CoordCursor = cursor Fast_Forward for
select distinct TARGET_ID, FULL_NAME, Email from vw_Coords where Email <> '' --and Target_ID = '7000001'
open #CoordCursor
fetch next from #CoordCursor into #Coord_ID,#Coord_Name, #Coord_Email
while ##FETCH_STATUS = 0
BEGIN
Print #Coord_ID + ' ' + #Coord_Email
set #emailBody = 'Member Renewal Transaction Activity for '+ #Coord_Name
DECLARE #RenewalActivity TABLE
(
Membership_Type varchar(25),
Member_ID varchar(20),
Chapter varchar(20),
Full_Name varchar(35),
Transaction_Date smalldatetime,
Renewal_Date smalldatetime,
AC_ID varchar(10),
AC_Name varchar(30)
)
insert into #RenewalActivity(Membership_Type, Member_ID, Chapter, Full_Name, Transaction_Date, Renewal_Date, AC_ID, AC_Name)
exec #sqlCommand #Coord_ID
if OBJECT_ID('tempdb..##temprenewals') is not null
drop table ##temprenewals
select * into ##temprenewals from #RenewalActivity
set #qry = 'select * from ##temprenewals'
EXEC msdb.dbo.sp_send_dbmail
#profile_name = 'Admin',
#recipients = #Coord_Email,
#query = #qry,
#execute_query_database = 'TOPS',
#subject = 'New Members and Renewals',
#body = #emailBody,
#attach_query_result_as_file = 1,
#query_attachment_filename='coord-s-9.csv',
#query_result_separator=#tab,
#query_result_no_padding=1
fetch next from #CoordCursor into #Coord_ID,#Coord_Name, #Coord_Email
END
close #CoordCursor
deallocate #CoordCursor
1st issue; the recipients receive the report contains all the data. as they should receive just what it related to them
example:
Member_ID | Chapter |Coord_Email
--------------------------------------
1 | A05 | Coord2#Email.com
5 | A01 | Coord1#Email.com
8 | A05 | Coord2#Email.com
12 | A01 | Coord1#Email.com
Currently 1,5,8 and 12 go to Coord1 and Coord2. the intention is 5 and 12 associated with A01 go to Coord1 and 1 and 8 go to Coord2.
2nd issue; the db mail is successfully queued as it stated in the log with 35 recipients. However, not all the recipients was included in the mail. Out of 90 recipients only 35 received the emails. i checked the 1st query and it resulted all the recipients "90".
Thank you in advance

email from SQL server are wrong

I am using SQL Server 2008 and am trying to send emails to customers about their overdue ADV returns. There is a 30 day, 45 day and 50 day letter. I have noticed this issue currently on the 30 day and 45 day letters.
I have a query that pulls the right people. For instance on the 30 day letter today it pulled 4 records and they are correct. for instance the data looks like
john item1
david item1
david item2
fred item1
So what is happening is I get 4 emails, but john is missing and david gets 3 emails one of which is a duplicate.
Here is the code for sending the emails
OPEN C1
FETCH NEXT FROM C1
INTO #sronum, #transdate,#item,#desc, #days, #email, #NAME
WHILE ##FETCH_STATUS = 0
BEGIN
FETCH NEXT FROM C1
INTO #sronum, #transdate,#item,#desc,#days, #email, #NAME
set #email = 'internal test email address'
set #subject = 'ADV Return is 30 days past due'
set #body = 'Dear ' + #name + ', </br></br>' + more text
EXEC msdb.dbo.sp_send_dbmail
#recipients = #email
,#Body = #Body
,#subject = #Subject
,#body_format = 'html'
,#exclude_query_output = 1
END
CLOSE C1
DEALLOCATE C1
A bit commented;
OPEN C1
-- Fetch first result and throw it away since next fetch will be done
-- before using the values
FETCH NEXT FROM C1 INTO
#sronum, #transdate,#item,#desc, #days, #email, #NAME
-- If the fetch went well, loop
WHILE ##FETCH_STATUS = 0
BEGIN
-- Fetch the next row and ignore if it went well for now
FETCH NEXT FROM C1 INTO
#sronum, #transdate,#item,#desc,#days, #email, #NAME
set #email = 'internal test email address'
set #subject = 'ADV Return is 30 days past due'
set #body = 'Dear ' + #name + ', </br></br>' + more text
-- Send a mail to the possibly valid address
EXEC msdb.dbo.sp_send_dbmail
#recipients = #email
,#Body = #Body
,#subject = #Subject
,#body_format = 'html'
,#exclude_query_output = 1
-- Jump back to the start of the loop to check if the mail just sent
-- was supposed to be sent.
END
CLOSE C1
DEALLOCATE C1
The simplest fix is to move the second fetch after the email has been sent. That will check if the first result was valid, send a mail, fetch a new row and go back to the validity check to possibly send another mail.