At times I have seen in SSIS forums people ask about the way they can know the number of records updated by a query or deleted by a query in an Execute SQL Task in control flow. Even I replied at times that its not possible(in a direct manner), until I read about the property ExecValueVariable.
In the SSIS Forum I often
find people asking if it’s possible to send mail in HTML format or Fetch data
from Table and use it in the mail body. In the Send Mail Task we can only send
the mails in text format or send the query result as an attachment.
Today I will explain the way this
can be achieved.
If we have a table with columns
as ID, CustName, Amount and we need to have the mail sent in the following
format. The rows will be colored based on a particular condition which can be
set in the query.
Mail Header
ID
CustomerName
Amount
1
Sudeep
100
2
Ankur
-10
3
Manju
20
Source Table Script
CREATE TABLE [dbo].[tblCust]( [ID] [int] IDENTITY(1,1) NOT NULL, [CustName] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, [Amount] [int] NULL ) ON [PRIMARY]
Insert Records
INSERT INTO [RAJ].[dbo].[tblCust]([CustName],[Amount]) ( SELECT 'Sudeep',100 UNION ALL SELECT 'Ankur',-10 UNION ALL SELECT 'Manju',3 )
First we set up the Database Mail Profile with the following query
in our SQL server.
USE msdb
GO
DECLARE @ProfileName VARCHAR(255)
DECLARE @AccountName VARCHAR(255)
DECLARE @SMTPAddress VARCHAR(255)
DECLARE @EmailAddress VARCHAR(128)
DECLARE @DisplayUser VARCHAR(128)
--Here I am setting up our Profile Name, Account Name, STMP server
name, and the name that will display in the from field in the e-mail.
SET @ProfileName = 'Sudeep';
SET @AccountName = 'Sudeep';
SET @SMTPAddress = '192.168.1.101';
SET @EmailAddress = 'rajsudeep@gmail.com';
SET @DisplayUser = 'SQL Mail';
--The following section adds our Account, Profile, and
Profile-Account association to the system.
EXECUTE
msdb.dbo.sysmail_add_account_sp
@account_name = @AccountName,
@email_address = @EmailAddress,
@display_name = @DisplayUser,
@mailserver_name = @SMTPAddress
EXECUTE
msdb.dbo.sysmail_add_profile_sp
@profile_name = @ProfileName
EXECUTE
msdb.dbo.sysmail_add_profileaccount_sp
@profile_name = @ProfileName,
@account_name = @AccountName,
@sequence_number = 1 ;
Next is the query that provides us our data in HTML format which will
be used in the mail body. DECLARE @tableHTML NVARCHAR(MAX) ; SET @tableHTML = N'<html><body><h1>Mail Header</h1>' + N'<table border="1" width="100%">' + N'<tr bgcolor="gray"><td>ID</td><td>CustomerName</td><td>Amount</td></tr>' + CAST(( SELECT td = ID, '', td = CustName, '', 'td/@bgcolor'=CASE WHEN Amount>0 THEN 'Green' ELSE 'Red' END, td = Amount, '' FROM tblCust FOR XML PATH('tr'), TYPE) AS NVARCHAR(MAX)) + N'</table></body></html>'EXEC msdb.dbo.sp_send_dbmail @recipients='<MailID@maildomain.Com>', @subject = 'SQL Errors Report', @body = @tableHTML, @body_format = 'HTML', @profile_name = 'SudeepTest';
In this query the HTML body is
formed in the variable @tableHTML, and the body format is set to ‘HTML’.
Depending on the number of records fetched in the query the HTML body that is created
from the above query would looks like:
<html>
<body>
<h1>
Mail Header</h1>
<tableborder="1"width="100%">
<trbgcolor="gray">
<td>
ID</td>
<td>
CustomerName</td>
<td>
Amount</td>
</tr>
<tr>
<td>
1</td>
<td>
Sudeep</td>
<tdbgcolor="Green">
100</td>
</tr>
<tr>
<td>
2</td>
<td>
Ankur</td>
<tdbgcolor="Red">
-10</td>
</tr>
<tr>
<td>
3</td>
<td>
Manju</td>
<tdbgcolor="Green">
3</td>
</tr>
</table>
</body>
</html>
If you need any kind of
modification in your table look and feel you could think about the related HTML
that you need and modify the above query accordingly.
Now in the SSIS Package that you
have use the 2nd query in Execute SQL Task and check the mail that you receive.
It is not necessary that it can
be used for tables. You can modify the select statement
in the above query to return the data as HTML format without FROM clause or simply put your HTML code in the @tableHTML variable.
Prerequisites:
·The SMTP server should be installed and configured
·The user in the profile should have access to
the SMTP Server
·Check the SMTP server for the domains to which
it can broadcast mails.
I am uploading a few sample packages that you could use and modify as per your requirement. Let me know if you need any specific sample or any change in these packages.
This package shows an example where the file connection is changed dynamically based on inputs from the database table. This package includes Execute SQL Task, Foreach Loop with ADO Enumerator, Data Flow Task including Flat File Connection Manager, Derived Column for date transformation, OLEDB Destination and Flat File destination for error records. For step by step description check this post.
This package picks files from folder and deletes files based on the file name. It makes use of Foreach Loop, dummy Script Task, Precedence Constraint and File System Task.
This is a simple package where I just show how we remove duplicates from the records and perform lookup with no caching. This package includes Sort Transform, Lookup Transform, Flat File Source and OLEDB Destination.
QueryFromFile.dtsx This package executes a set of queries kept in a folder using For Each Loop and Execute SQL Task
I will be uploading more samples soon.
Update1: SQLXMLtoFile.dtsx This package takes a XML stream from Execute SQL task as output and uploads the file to a XML File. The SQL Query could be of any form like: SELECT * FROM Table1 FOR XML Auto or SELECT * FROM Table1 FOR XMLPATH('Test')
Update2: DeleteOldestFile.dtsx This package will delete the oldest file from a given folder. The filename is of the format File_MMDDYYYY.txt For more details on this package I will be posting a blog soon.
In the SSIS forum very often there are questions on dynamic name for a flat file connection manager
I have split it in two parts:
A single file name needs to be set up dynamically
Multiple file names need to be set up dynamicallyper execution.
In this post I will talk about the first scenario.
Scenario:
For simplicity sake I will be using a case where the file name is saved in a DB table.
Need to fetch the file name from a database table.
Need to use a Data Flow Task which has a Flat File Source.
This flat file source needs the file name to be set up dynamically at run time.
The folder for the file is fixed.
Create a string Variable: FileName with the scope as the package(Practice in my case). Set the value of the variable to a file name that exists (I set it to Demo.txt) just while development.
Now set up the Flat File Connection Manager for the above file that exists and has the same meta data as the file that will be used later.
File name: Click on the Browse button and select the file.
I am using the other default settings.
Click on the Columns tab to verify the columns.
Then click OK.
To set up the Execute SQL task to fetch the file name and save it to a user variable FileName.
In the Execute SQL task Editor window go to the General tab.
Do the following settings: ResultSet : Single row. ConnectionType : OLEDB(that’s what I have used you could also use ADO.NET) Connection : Select the appropriate one. Put the query to get the single file name from the table.
Now select the Result Set tab
Click the Add Button.
You will see the below screen with a row for the result details.
In the Result Name set it to : 0 (Numeric zero)
In the Variable Name select the string type variable which has the scope set to the package.
Once this is done click OK.
Now select the Flat File Connection Manager 1 and click "F4" or right click and select “Properties”.
In the properties pane for the above connection manager:
Set the DelayValidation to True
Expand the Expressions by clicking the ellipse.
On the Property Expressions Editor window:
In the Property column select the ConnectionString property from the drop down list.
Now expand the Expression column by clicking the ellipse. An Expression Builder window will pop up.
On the Expression Builder window:
Set the Expression as: “C:\\Data\\” + @[User::FileName]
Click the Evaluate expression button at the left hand bottom to see if the expression is creating the desired output.
Click OK.
Click OK on the Property Expression Editor as well.
Now set up the Data Flow Task as below:
Double click the Flat File Source.
In the Flat File Source Editor:
In the Connection Manager tab, select the appropriate Flat file connection manager from the drop down list.
Now in the OLEDB Task:
Select the OLEDB Connection needed to connect to the destination Data base.
Select the table where the columns need to be inserted.
Goto the mapping
Go the mapping and do the mapping as required and click OK.
Save and build the package. Now when you execute the package the package will take the filename from the DB table.
This could also be modified by having the file name stored directly to a variable and make this variable configurable.
Very soon I will be posting on setting up file names dynamically for multiple files.