I use the #query perimeter in sp_send_dbmail to send out an e-mail with a list of warnings (the warnings are returned by the #query perimeter). The #query perimeter is listed as text in the e-mail. All of the records returned from the #query perimeter and displayed in the e-mail has a line break between them. ie. If I have 4 records, I would have 8 lines because of line breaks.
How do I turn the line breaks off? I read the the msdn article for sp_send_dbmail, but it didn't mention any attributes that could be changed that would affect the line breaks.
Code:
BEGIN
EXEC MSDB.DBO.sp_send_dbmail
#PROFILE_NAME = 'Alerts',
#RECIPIENTS = #MAIL,
#SUBJECT = #NEWSUBJECT,
#BODY = #NEWBODY,
#QUERY =
'SET NOCOUNT ON
DECLARE #HEXSTRING AS VARCHAR(100)
SET #HEXSTRING = (SELECT HEXADECIMAL_STRING FROM mydb.dbo.statusupdates
WHERE MACHINE_ID = ''1111'' AND DATEDIFF(MI, TIME_DATE_RECEIVED, GETDATE()) <= 60)
SELECT [Warning_Description] FROM mydb.DBO.BINARYTOTABLE(mydb.DBO.HEXTOBINARY(#HEXSTRING)) AS ABB1
JOIN mydb.DBO.WarningMessages ON mydb.DBO.WarningMessages.[Bit_Offset] = ABB1.BITPLACE
WHERE BITVALUE = 1 AND ALERT_LEVEL = ''WARNING''',
#QUERY_RESULT_HEADER = 0,
#ATTACH_QUERY_RESULT_AS_FILE = 0;
END
Old post, but probably worth checking #query_result_width parameter of sp_send_dbmail
See http://technet.microsoft.com/en-us/library/ms190307(v=sql.110).aspx
If the data width in a column exceeds #query_result_width (default of 256) a new line will be added.
Steve
I have always used CHAR(13)+CHAR(10) to create line breaks in tsql. You will have to replace it by ' '.
I ended up putting everything into the #BODY parameter of SP_SEND_DBMAIL. Query results from a SELECT statement could be concatenated with regular text into a string and you can use HTML to format the resulting text.
try this and see what you get ...
#query = REPLACE(#query,CHR(13),'')
Related
I am using msdb.dbo.sp_send_dbmail to send email based upon query results. It works fine until I used and isnull in my query. The query returns the right results but a message is not triggered. When the field in question is not null it works fine.
I want to validate builddate against checkdate. When they do not match I want to send an email. I used isnull for cases when the table did not populate and builddate is null.
My base query is as follows:
SELECT
ISNULL(MAX(convert(date,Builddate)),DATEADD(YEAR,-10,GETDATE())) AS
[builddate],
CONVERT(VARCHAR(10),GETDATE(),121)AS [checkdate]
FROM dbo. XXXX_BPCCustomer_Test
HAVING ISNULL(MAX(convert(date,Builddate)),DATEADD(YEAR,-10,GETDATE()))
<>CONVERT(VARCHAR(10),GETDATE(),121)
the results are builddate=2010-01-03 and checkdate = 2020-01-3
the code that pushes the email is as follows:
DECLARE #recordcount INT
SELECT #recordcount = ISNULL(COUNT(*),0)
FROM [YCH-REPORTING\YCHANALYTICS].[x3v7].[dbo].[Dataset_BPCCustomer_Test]
HAVING ISNULL(MAX(convert(date,Builddate)),DATEADD(YEAR,-10,GETDATE()))
<>CONVERT(VARCHAR(10),GETDATE(),121)
IF (#recordcount > 0)
BEGIN
EXEC msdb.dbo.sp_send_dbmail
#profile_name = 'SQL Mail',
#recipients = 'john.XXXXXXXXX.com;XXXXXXXXXXXXXXX',
#query = 'SELECT
ISNULL(MAX(convert(date,Builddate)),DATEADD(YEAR,-10,GETDATE())) AS
[builddate],
CONVERT(VARCHAR(10),GETDATE(),121)AS
[checkdate],"Dataset_BPCCustomer_Test" as [Table]
FROM [XXXXXX\YCHANALYTICS].[x3XX].[dbo].
[Dataset_BPCCustomer_Test]
HAVING
ISNULL(MAX(convert(date,Builddate)),DATEADD(YEAR,-10,GETDATE()))
<>CONVERT(VARCHAR(10),GETDATE(),121)'
,
#subject = ' DataSet did not update or isnull',
--#attach_query_result_as_file = 1,
--#query_result_header = 0,
#body =0;
END
It appears that it is not processing the isnull statement? Any suggestions and thanks in advance.
It looks like there are double-quotes ("Dataset_BPCCustomer_Test") inside #query, making the statement incorrect.
Those should each be two single quotes (apostrophes):
#query = 'SELECT
ISNULL(MAX(convert(date,Builddate)),DATEADD(YEAR,-10,GETDATE())) AS
[builddate],
CONVERT(VARCHAR(10),GETDATE(),121)AS
[checkdate],''Dataset_BPCCustomer_Test'' as [Table]
FROM [XXXXXX\YCHANALYTICS].[x3XX].[dbo].
[Dataset_BPCCustomer_Test]
HAVING
ISNULL(MAX(convert(date,Builddate)),DATEADD(YEAR,-10,GETDATE()))
<>CONVERT(VARCHAR(10),GETDATE(),121)'
I have a code to send Birthday Emails to Customers, the query works fine, but the SQL Mail server always send a Birthday Email to all Customers, even he has no Birthday
use Insurance
go
select
Customer.CustomerID
,Customer.FirstName
,Customer.LastName
,Customer.Birthday
,Customer.Email
from Customer
where Customer.CustomerID = Customer.CustomerID and
DAY([Birthday]) = DAY(GETDATE())
AND MONTH([Birthday]) = MONTH(GETDATE())
declare #Receipientlist nvarchar(4000)
set #Receipientlist =
STUFF((select ';' + Email FROM dbo.Customer FOR XML PATH('')),1,1,'')
EXEC msdb.dbo.sp_send_dbmail #profile_name='test',
#recipients=#Receipientlist,
#subject='Insurance',
#body='Happy Birthday.
Today is your Birthday.'
Your query at the top of your batch has nothing to do with your statement that executes msdb.dbo.sp_send_dbmail. If you only want to email customer's who's birthday it is, you need to filter in the statement that creates the recipients (and you don't need the previous statement):
DECLARE #RecipientList nvarchar(4000);
--I removed the CustomerID = CustomerID clause, as it'll always equal itself,
--apart from when it's value is NULL (and I doubt it'll ever be NULL)
SET #RecipientList = STUFF((SELECT N';' + Email
FROM dbo.Customer
WHERE DAY([Birthday]) = DAY(GETDATE())
AND MONTH([Birthday]) = MONTH(GETDATE())
FOR XML PATH(N''),TYPE).value('.','nvarchar(4000)'), 1, 1,N'');
EXEC msdb.dbo.sp_send_dbmail #profile_name = 'test',
#recipients = #RecipientList,
#subject = 'Insurance',
#body = 'Happy Birthday.
Today is your Birthday.';
I've also changed the way that the value from the subquery is returned, used TYPE and the value clauses. Email addresses can contain some special characters, and these would have been escaped without the usage of TYPE (for example & would become &). (I've also corrected the spelling of #RecipientList.)
I'm creating a task to send an email with a SQL output as a csv file attached in the SQL Server Agent. Normally not a problem, my code looks like this:
declare #tab char(1) = char(9)
EXEC msdb.dbo.sp_send_dbmail
#profile_name = 'MailProfile',
#recipients = 'email#email.com',
#subject = 'TheSubject',
#body = 'TheBody',
#query = 'select * from ##TempTableBeingUsed',
#Attach_Query_result_as_file = 1,
#query_attachment_filename = 'report.csv',
#query_result_separator = #tab,
#query_result_no_padding=1,
#exclude_query_output=0,
#append_query_error =0,
#query_result_header=1
And this normally works, but with the current query the column names are line wrapping, and a lot of the data rows are line wrapping, without a line break being present. It looks like it does this whenever the length of the row is more then 255 characters. Is there any way to bypass this? Looks it may be the same as this issue, SQL Email to CSV, Results have Line Splitting issues.
Adding the option:
#query_result_width=500
fixed it
I have the following table:
CREATE TABLE [dbo].[MyTable](
[Day_ID] [nvarchar](50) NULL,
[SAS] [nvarchar](50) NULL,
[STAMP] [datetime] NULL DEFAULT (getdate())
)
which contains this data:
'2017_12_06_01','Red'
'2017_12_06_02','Yellow'
'2017_12_06_03','Green'
'2017_12_06_04','Blue'
I also have a SP which read all the data from MyTable and send it in the body of an e-mail message.
SET NOCOUNT ON;
EXEC msdb.dbo.sp_send_dbmail
#profile_name = 'MyMailProfile'
,#recipients = 'me#account.com'
,#subject = 'This is the object'
,#body = 'This is the body:'
,#body_format = 'TEXT'
,#query = 'SET NOCOUNT ON select [Day_ID],[SAS] from MyTable SET NOCOUNT OFF'
,#attach_query_result_as_file = 0
,#query_result_separator = '|'
,#exclude_query_output = 1
,#query_result_no_padding = 0
,#query_result_header = 0
,#append_query_error=1
Everything works but my problem is that in the body the results appear like these:
2017_12_06_01 |Red
2017_12_06_02 |Yellow
2017_12_06_03 |Green
2017_12_06_04 |Blue
In other words SQL Server know that the columns could be 50 characters long so they fill the space that doesn't contain characters with spaces. This is very boring if you consider that happen also if you write numeric values into a column, for example, NUMERIC.
I've tried with LTRIM and RTRIM but nothing changed.
I am using SQL Server 2005.
The parameter #query_result_no_padding should allow you to do this.
Change it from:
#query_result_no_padding = 0
to
#query_result_no_padding = 1
[ #query_result_no_padding ] #query_result_no_padding The type is bit.
The default is 0. When you set to 1, the query results are not padded,
possibly reducing the file size.If you set #query_result_no_padding to
1 and you set the #query_result_width parameter, the
#query_result_no_padding parameter overwrites the #query_result_width
parameter. + In this case no error occurs. If you set the
#query_result_no_padding to 1 and you set the #query_no_truncate
parameter, an error is raised.
Source: https://learn.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/sp-send-dbmail-transact-sql
You need to run two queries - first to compute the actual lengths, the second to retrieve the data for the email. Obviously, this can have a high cost.
Something like:
declare #maxDay int
declare #maxSAS int
select #maxDay = MAX(LEN(RTRIM(Day_ID))),#maxSAS = MAX(LEN(RTRIM(SAS))) from MyTable
declare #sql varchar(max)
set #sql = 'SET NOCOUNT ON select CONVERT(nvarchar(' + CONVERT(varchar(10),#maxDay) +
'),[Day_ID]) as Day_ID,CONVERT(nvarchar(' + CONVERT(varchar(10),#maxSAS) +
'),[SAS]) as SAS from MyTable SET NOCOUNT OFF'
And then use #sql in you sp_send_dbmail call.
I've tried with LTRIM and RTRIM but nothing changed.
It wouldn't. Each column in a result set has a single fixed type. The input to your e.g. RTRIM() calls is an nvarchar(50). Without knowing the contents of all rows, what possible data type can SQL Server derive for the output from that RTRIM() using expression? It can only still be nvarchar(50) and so that's still the type of the column in the result set. For all the server nows, there could be a row containing 50 non-whitespace characters and the result still needs to show that.
Let's imagine that I have a table ExchangeSession with field Processed.
I need to send e-mail with all ExchangeSession with Processed = 0 and then update these sessions to Processed = 1. Like this:
EXEC msdb.dbo.sp_send_dbmail
#profile_name = 'SomeProfile',
#recipients='SomeAddress',
#subject = 'SomeSubject',
#body = #bodyparam,
#body_format = 'TEXT',
#query = N'SET NOCOUNT ON; select * from ExchangeSession where Processed = 0',
#execute_query_database = #dbnameparam,
#attach_query_result_as_file = 1,
#query_attachment_filename = 'report.csv',
#query_result_header = 1,
#query_result_width = 32767,
#query_result_separator = #delimiterparam,
#exclude_query_output = 1,
#append_query_error = 0,
#query_no_truncate = 0,
#query_result_no_padding = 1;
update ExchangeSession
set
Processed = 1
where
Processed = 0
Will sp_send_dbmail executes my query synchronously relatively to the batch or asynchronously? In other words is there any chance that in the e-mail I'll not get all unprocessed sessions?
The answer is YES. query param execution is synchronous relatively to the batch.
Made the following test:
insert dbo.[CallLog]([Name]) values ('BeforeMail')
set #queryparam = N'SET NOCOUNT ON;
insert dbo.[CallLog]([Name]) values (''Attachment'');
SELECT
0 as [ID],
...'
...
EXEC msdb.dbo.sp_send_dbmail
...
#query = #queryparam,
...
insert dbo.[CallLog]([Name]) values ('AfterMail')
And voila, the results in CallLog:
LogID Name
801 BeforeMail
802 Attachment
803 AfterMail
Also I looked at sysmail_allitems and sysmail_mailattachments. The send_request_date value in the sysmail_allitems is exactly the same as last_mod_date value in the sysmail_mailattachments.
And the value of sent_date in the sysmail_allitems slightly differs.
So sp_send_dbmail executes the query synchronously in the batch, saves results into a file and then later on send an e-mail.
I am not 100% certain, but I would assume that it is possible that new entries could sneak into your ExchangeSession table between sending the email and updating the records. I would play safe by doing:
update ExchangeSession
set Processed = 2 -- This procedure should be the only place that sets Processed to 2
where Processed = 0
EXEC msdb.dbo.sp_send_dbmail
....
#query = N'SET NOCOUNT ON; select * from ExchangeSession where Processed = 2',
....
update ExchangeSession
set Processed = 1
where Processed = 2