Link to home
Start Free TrialLog in
Avatar of Michael Purdham
Michael PurdhamFlag for United Kingdom of Great Britain and Northern Ireland

asked on

Summarising data in a query using sp_send_dbmail

I have written a simple query to email data using sp_send_dbmail as per the example in Experts Exchange.
I need to add another row at the bottom of the table(s) in which I can summarise the data in the column above e.g. sum Qty or Line Val

Help would be much appreciated.
Thanks.

DECLARE @tableHTML  NVARCHAR(MAX);

SET @tableHTML =
 N'
      
<head>
      <STYLE TYPE="text/css">

p.title{font-family:arial;font-size:12pt;color:blue;font:bold}
th{font-family:arial;font-size:10pt;color:white;background-color:blue;text-align:left;padding-right:10px}
.data{font-family:arial;font-size:8pt;color:black;background-color:white;border:1px solid black;text-align:left;padding-right:20px}
.datara{font-family:arial;font-size:8pt;color:black;background-color:white;border:1px solid black;text-align:right;padding-left:10px}
</STYLE>
</head>
      <p class="title">Sales Report UK</p>
    <table>
    <tr>
    <th>Period</th>
    <th>Posting Date</th>
    <th>Salesperson</th>
    <th>Ship To Customer</th>
    <th>Item.....</th>
    <th>Description</th>
    <th>Qty</th>
    <th>Value (£)</th></tr>' +
    CAST ( ( SELECT
                              [td/@class]='data',
                td = Period,
                "*"='',
                [td/@class]='data',
                td = [Posting Date],
                "*"='',
                [td/@class]='data',
                td = Salesperson,
                "*"='',
                [td/@class]='data',
                td = Customer,
                "*"='',
                [td/@class]='data',
                td = Item,
                "*"='',
                [td/@class]='data',
                td = Description,
                "*"='',
                [td/@class]='datara',
                td = Qty,
                "*"='',
                [td/@class]='datara',
                td = [Line Val (LCY)]

              FROM [$ UK Sales Analysis] AS SA
              WHERE [Product Series]='ProductA'
              ORDER BY Period,[Posting Date],Salesperson,Customer
              --GROUP BY Period
              --ORDER BY [Product Series]
             
              FOR XML PATH('tr'), TYPE
    ) AS NVARCHAR(MAX) ) +
    N'</table>
    <p class="title">Sales Report France</p>
    <table class="table">
    <tr class="header">
    <th>Period</th>
    <th>Posting Date</th>
    <th>Salesperson</th>
    <th>Ship To Customer</th>
    <th>Item</th>
    <th>Description</th>
    <th>Qty</th>
    <th>Value(€)</th></tr>' +
    CAST ( ( SELECT
                              [td/@class]='data',
                td = Period,
                "*"='',
                [td/@class]='data',
                td = [Posting Date],
                "*"='',
                [td/@class]='data',
                td = Salesperson,
                "*"='',
                [td/@class]='data',
                td = Customer,
                "*"='',
                [td/@class]='data',
                td = Item,
                "*"='',
                [td/@class]='data',
                td = Description,
                "*"='',
                [td/@class]='datara',
                td = Qty,
                "*"='',
                [td/@class]='datara',
                    td = [Line Val (€)]
              FROM [$ FR Sales Analysis] AS SA
              WHERE [Product Series]='ProductA'
              ORDER BY Period,[Posting Date],Salesperson,Customer
              --GROUP BY Period
              --ORDER BY [Product Series]
             
              FOR XML PATH('tr'), TYPE
    ) AS NVARCHAR(MAX) ) +
    N'</table> '

EXEC msdb.dbo.sp_send_dbmail
      @recipients='xxx@yyy.com',
    @subject = 'Sales Report',
    @body = @tableHTML,
    @body_format = 'HTML',
      @profile_name ='SQL'
Avatar of jimtpowers
jimtpowers
Flag of United States of America image

I would be inclined to incapsulate this into a stored procedure. Inside the sp, create a temporary table matching your output. Insert the rows from the UK query then, insert another row with the totals. Repeat the process for France. For example:

DECLARE @UKOut TABLE(Period VARCHAR(50),
[Posting Date] VARCHAR(50),
Salesperson VARCHAR(50),
Customer VARCHAR(50),
Item VARCHAR(50),
Description VARCHAR(50),
Qty VARCHAR(50),
[Line Val (LCY)] VARCHAR(50));

INSERT INTO @UKOut
SELECT Period,
[Posting Date],
Salesperson,
Customer,
Item,
Description,
Qty,
[Line Val (LCY)]
FROM [$ UK Sales Analysis] AS SA
WHERE [Product Series]='ProductA'
ORDER BY Period,[Posting Date],Salesperson,Customer;

INSERT INTO @UKOut (Qty, [Line Val (LCY)])
SELECT SUM(Qty),
SUM([Line Val (LCY)])
FROM [$ UK Sales Analysis] AS SA
WHERE [Product Series]='ProductA';

Once you have your temporary tables, use these in your statement to populate @tableHTML. One thing to note that took me hours to find. Even though you have defined @tableHTML as NVARCHAR(MAX), you can't add chunks any larger than 8,000 (if memory serves correctly) characters at a time. So, you'll want to modify your code to be something like:

SET @tableHTML =
 N'
     
<head>
      <STYLE TYPE="text/css">

p.title{font-family:arial;font-size:12pt;color:blue;font:bold}
th{font-family:arial;font-size:10pt;color:white;background-color:blue;text-align:left;padding-right:10px}
.data{font-family:arial;font-size:8pt;color:black;background-color:white;border:1px solid black;text-align:left;padding-right:20px}
.datara{font-family:arial;font-size:8pt;color:black;background-color:white;border:1px solid black;text-align:right;padding-left:10px}
</STYLE>
</head>
      <p class="title">Sales Report UK</p>
    <table>
    <tr>
    <th>Period</th>
    <th>Posting Date</th>
    <th>Salesperson</th>
    <th>Ship To Customer</th>
    <th>Item.....</th>
    <th>Description</th>
    <th>Qty</th>
    <th>Value (£)</th></tr>';

SET @tableHTML = @tableHTML +
...add the next logical group of lines here, probably the select statement for the table.

Keep adding each "logical group" like this so you are not adding more than 8,000 characters at a time.

One more thing to note with HTML emails: web clients such as Gmail strip out all of your styles and only keep the body of your message. We have had to style each individual tag to get our emails to display correctly for client based email as well as web based email.
Avatar of Michael Purdham

ASKER

Thanks. I have already fallen foul of the HTML formatting in different mail clients. It's a pain!

Your suggestion works weel, although I'll have to play around creating the 'logical groups' to which you refer.

What I do find is that the second insert into UKOut for the sum inserts at the top of the table.

What I have so far is this.

DECLARE @UKOut TABLE(Period VARCHAR(50),
[Posting Date] VARCHAR(50),
Salesperson VARCHAR(50),
Customer VARCHAR(50),
Item VARCHAR(50),
Description VARCHAR(50),
Qty VARCHAR(50),
[Line Val (LCY)] VARCHAR(50));

INSERT INTO @UKOut
SELECT Period,
[Posting Date],
Salesperson,
Customer,
Item,
Description,
Qty,
[Line Val (LCY)]
FROM [$ UK Sales Analysis] AS SA
WHERE [Product Series]='ProductA'
ORDER BY Period,[Posting Date],Salesperson,Customer;

INSERT INTO @UKOut (Qty, [Line Val (LCY)])
SELECT SUM(Qty),
SUM([Line Val (LCY)])
FROM [$ UK Sales Analysis] AS SA
WHERE [Product Series]='ProductA';


DECLARE @tableHTML  NVARCHAR(MAX);
SET @tableHTML =
 N'
      
<head>
      <STYLE TYPE="text/css">

p.title{font-family:arial;font-size:12pt;color:blue;font:bold}
th{font-family:arial;font-size:10pt;color:white;background-color:blue;text-align:left;padding-right:10px}
.data{font-family:arial;font-size:8pt;color:black;background-color:white;border:1px solid black;text-align:left;padding-right:20px}
.datara{font-family:arial;font-size:8pt;color:black;background-color:white;border:1px solid black;text-align:right;padding-left:10px}
</STYLE>
</head>
      <p class="title">Sales Report UK</p>
    <table>
    <tr>
    <th>Period</th>
    <th>Posting Date</th>
    <th>Salesperson</th>
    <th>Ship To Customer</th>
    <th>Item.....</th>
    <th>Description</th>
    <th>Qty</th>
    <th>Value (£)</th></tr>' +
    CAST ( ( SELECT
                              [td/@class]='data',
                td = Period,
                "*"='',
                [td/@class]='data',
                td = [Posting Date],
                "*"='',
                [td/@class]='data',
                td = Salesperson,
                "*"='',
                [td/@class]='data',
                td = Customer,
                "*"='',
                [td/@class]='data',
                td = Item,
                "*"='',
                [td/@class]='data',
                td = Description,
                "*"='',
                [td/@class]='datara',
                td = Qty,
                "*"='',
                [td/@class]='datara',
                td = [Line Val (LCY)]

              FROM @UKOut
             
              ORDER BY Period,[Posting Date],Salesperson,Customer
              --GROUP BY Period
              --ORDER BY [Product Series]
             
              FOR XML PATH('tr'), TYPE
    ) AS NVARCHAR(MAX) ) +
    N'</table>'
    EXEC msdb.dbo.sp_send_dbmail
      @recipients='xxx@yyy.com',
    @subject = 'LanXPLORER Sales Report',
    @body = @tableHTML,
    @body_format = 'HTML',
      @profile_name ='NAVSQL'
ASKER CERTIFIED SOLUTION
Avatar of jimtpowers
jimtpowers
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Tried as you suggested and now I have the summary values at the bottom.
Thanks.