SQL Job (Send Mail) - error formatting query probably invalid parameters - sql-server

I know this has come up a lot in the past but none of the fixes I've Googled or found on here has worked for me in this instance.
I'm running a fairly standard SQL Server Agent Job as a Transact-SQL script with the follow details: (replaced some stuff as *** for my boss's sanity)
-- Start T-SQL
USE msdb
EXEC sp_send_dbmail
#profile_name = 'MainProfile',
#recipients = 'test#test.co.uk',
#subject = 'T-SQL Query Result',
#execute_query_database = 'test30',
#query = 'SELECT ReferralReceivedDate,testRef,testcoMetadata.testcoRef,testcoMetadata.TimeSpentWithtester
FROM TestCasesTable, TestcoMetadata
WHERE testcasestable.CaseID = TestcoMetadata.CaseID AND AgencyName = [Test Injury] AND TestcoMetadata.TestcoRef IS NOT NULL AND TestcoRef <> ''
order by ReferralReceivedDate desc',
#attach_query_result_as_file=1,
#query_attachment_filename = 'Results.csv',
#query_result_separator = ','
-- End T-SQL --
The query itself runs fine as a normal query with no issues. The owner of this job has been used on other jobs again with no problems. In the step properties the Database selected is the same one as that mentioned in the #execute line.
I have a feeling this is either falling over the way it's trying to create the csv or something to do with permissions with dbmail part. I'm only a part time DBA so this has now lost me and I need help.

Replace this:
TestcoRef <> ''
With this:
TestcoRef <> ''''
You are creating dynamic sql, so you need to escape the single quotes.

So I never did get this working, but it turns out my boss already had something cooked up.
He had a stored procedure set up to run a batch file that was using an emailer exe to send the mail out, as its apparently better/more powerful than SQL mail.
I simply copied his S.P and amended it to include my query.

Related

TSQL - Only execute a line if run manually (not in job)

Can I make an IF statement that only executes when run manually from SSMS?
I have a SQL Server job that executes TSQL code. That TSQL code is maintained in a separate .sql text file. When it needs to be edited, I edit the text file and copy&paste the final results into the job.
This normally works very well but there is one critical line that is only used for testing (it sets a variable to a specific value). How can I guarantee that line only executes when run manually?
Is there something like If ManualExecution() then Blah?
IF APP_NAME() LIKE 'Microsoft SQL Server Management Studio%'
BEGIN
PRINT 'Running inside SSMS'
END;
If you use SQL Agent to run the job, it's app name should be SQLAgent - TSQL JobStep (Job 0x... : Step ...). If you use some other software, just make sure that it doesn't set its Application Name to "Microsoft SQL Server Management Studio"...
You can use the following code to get the SQL Server Agent JobId of the current process (otherwise NULL):
declare #JobId as UniqueIdentifier;
begin try
-- The executed statement will result in a syntax error if not in a SQL Server Agent job.
execute sp_executesql
#stmt = N'select #JobId = Cast( $(ESCAPE_NONE(JOBID)) as UniqueIdentifier );',
#params = N'#JobId UniqueIdentifier output',
#JobId = #JobId output;
end try
begin catch
if ##Error != 102 -- 102 = Syntax error.
select ##Error; -- Handle unexpected errors here.
end catch
select #JobId as JobId; -- NULL if not running as a SQL Server Agent job.
Note that the JobId can be used to access additional information about the current job in dbo.sysjobs.

Generic failure using sp_send_dbmail in SQL Server 2014

I'm trying to use sp_send_dbmail to send the results of a query through a SQLAgent job in SQL Server 2014. I believe I have my DBMail profile set up properly but when running this:
exec msdb.dbo.sp_send_dbmail
#profile = 'TestProfile',
#recipients = 'testmail#gmail.com',
#subject = 'Test',
#query = 'SELECT id FROM TestTable',
#attach_query_result_as_file = 1,
#query_attachment_filename = 'TestValues.txt'
I get the following error message:
Failed to initialize sqlcmd library with error number -2147467259.
Googling this error message didn't turn up anything useful, likely due to the generic error number. Anyone have some insight into this error message?
I found that despite both my query window (for testing) and SqlAgent job were pointing at my desired DB, sp_send_dbmail doesn't seem to have any database context. My original post was failing because SQL didn't know where to run SELECT * FROM TestTable. The fix is to provide sp_send_dbmail with database context by either fully qualifying your table in the #query parameter:
#query = 'SELECT id FROM testDB.dbo.TestTable'
or by providing the optional #execute_query_database parameter:
#execute_query_database = 'testDB'
Enable sysadmin server role for the account that is used to run the SQL Server Agent.Below are the screenshots.
Error
Fix
Now the SQL Server Job runs without any errors and I get an email from dbmail.
There's another reason why you might get this error; if the query has an issue.
In our case we had (note that it's not due to a syntax error; note the missing quotes):
DECLARE #EmailQuery varchar(max) = 'select
e.Field1,
REPLACE(REPLACE(e.ExceptionReason, CHAR(13), ''), CHAR(10), '') ExceptionReason,
e.UserName
from dbo.tblException e'
Once we corrected it as follows, it worked fine:
DECLARE #EmailQuery varchar(max) = 'select
e.Field1,
REPLACE(REPLACE(e.ExceptionReason, CHAR(13), ''''), CHAR(10), '''') ExceptionReason,
e.UserName
from dbo.tblException e'

SQL Server Agent - get my own job_id

I'm running a SQL Server 2008 64 bit Developer Edition with Service Pack 1 installed.
I have a SQL Server Agent Job. Within this job I want to get the job_id of my own job.
On MSDN (http://msdn.microsoft.com/en-us/library/ms175575(v=SQL.100).aspx) you can find a description of using tokens in job steps. Wow, great, that's what I'm looking for!! Just use (JOBID).
Since SQL Server 2005 SP1 you have to use macro like $(ESCAPE_NONE(JOBID)). No problem.
But if you try the example:
DECLARE #name NVARCHAR(128)
select #name = name from msdb.dbo.sysjobs where job_id = $(ESCAPE_SQUOTE(JOBID))
PRINT #name
you get:
Incorrect syntax near 'ESCAPE_SQUOTE'. (Microsoft SQL Server, Error: 102)
Ok, now from the scratch:
PRINT N'$(ESCAPE_SQUOTE(JOBID))'
results in 0xE33FE637C10B3C49A6E958BB3EF06959 but the job_id is
37E63FE3-0BC1-493C-A6E9-58BB3EF06959
The "N'" I think makes an implicit conversion to NVARCHAR of the (JOBID)...
Ok, I think I have to care about the datatype of (JOBID). In the book "SQL Server 2008 Administration" on page 168/169 there's also an example of using (JOBID):
declare #jobid binary(16)
SELECT #jobid =Convert(Uniqueidentifier,$(ESCAPE_NONE(JOBID)))
results in:
Incorrect syntax near '('. (Microsoft SQL Server, Error: 102)
I'm totally confused now. Could please someone help me with a good advice or solution. Every kind of help is appreciated.
Best regards
Helmut
We had trouble with this recently and did not go the route you found in MSDN. Instead, we recovered the jobid from dbo.sysjobs by name directly (the opposite of your example) and then used that within the job to check execution status (exiting out of long running while loop if job state had changed).
declare #jobid uniqueidentifier
SELECT #jobid = job_id from msdb.dbo.sysjobs where name = '[blah]'
thanks for your answers. The problem is that I tried to parse the statement in job step. Then I got this error. While running the job there's no problem.
My very best solution now is:
declare #JobID uniqueidentifier
SELECT #JobID = $(ESCAPE_NONE(JOBID));
PRINT 'My JobID is ' + Convert(char(255), #JobID)
Now you handle with #JobID, but as far as I know until now you have to convert always to char(255).
Thanks to user state_dba on MSDN.
Just forget what parser is saying - variable resolution is done at runtime. Parser does not know about that.
This may sound obvious, but I get the error you quoted from your first sample, if I run it in a query window, but it runs perfectly well when I paste that script into a job step.
You can only use these tokens within job steps. And, given that we're not expecting any quotes in the jobid token, I'd use ESCAPE_NONE whenever you reference it.
For those that need an alternative method to get your own job ID without macros, for example, from within a stored procedure that a job step calls. I found the following here
DECLARE #SQL NVARCHAR(72),
#jobID UNIQUEIDENTIFIER,
#jobName SYSNAME
IF SUBSTRING(APP_NAME(),1,8) = 'SQLAgent'
BEGIN
SET #SQL = 'SET #guid = CAST(' + SUBSTRING(APP_NAME(), 30, 34) + ' AS UNIQUEIDENTIFIER)'
EXEC sp_executesql #SQL, N'#guid UNIQUEIDENTIFIER OUT', #guid = #jobID OUT
SELECT #jobName = name
FROM msdb..sysjobs
WHERE job_id = #jobID
END

sql server send output messages by email

I have been running up a stored procedure that runs several separate update and insert statements. It also prints some status messages that I can see in sql management studio. I am going to automate this procedure to run overnight but need the output as a final check to be sent to me.
I know how to use the email stored procedure and have that working but can't find where the message output i.e. (10 rows affected)... is all stored.
Informational messages like '10 rows affected' or PRINT output are sent straight to the client and you can't capture it in Transact-SQL. You can, however, be the client if you are a CLR procedure, and in that case you will get all the output from the procedure you invoked. Requires SQL Server 2005 or newer for CLR.
A much better alternative is to have the procedure create a true output, like a rowset result or output parameters.
you can always store the output in a table
exec master..xp_sendmail
#recipients = 'you#you.com',
#subject = 'my alert'.
#query = 'select * from mytable'
you can't get information messages from t-sql.
PRINT #WIDELOAD

Help with sp_msforeachdb -like queries

Where I'm at we have a software package running on a mainframe system. The mainframe makes a nightly dump into sql server, such that each of our clients has it's own database in the server. There are a few other databases in the server instance as well, plus some older client dbs with no data.
We often need to run reports or check data across all clients. I would like to be able to run queries using sp_msforeachdb or something similar, but I'm not sure how I can go about filtering unwanted dbs from the list. Any thoughts on how this could work?
We're still on SQL Server 2000, but should be moving to 2005 in a few months.
Update:
I think I did a poor job asking this question, so I'm gonna clarify my goals and then post the solution I ended up using.
What I want to accomplish here is to make it easy for programmers working on queries for use in their programs to write the query using one client database, and then pretty much instantly run (test) code designed and built on one client's db on all 50 or so client dbs, with little to no modification.
With that in mind, here's my code as it currently sits in Management Studio (partially obfuscated):
use [master]
declare #sql varchar(3900)
set #sql = 'complicated sql command added here'
-----------------------------------
declare #cmd1 varchar(100)
declare #cmd2 varchar(4000)
declare #cmd3 varchar(100)
set #cmd1 = 'if ''?'' like ''commonprefix_%'' raiserror (''Starting ?'', 0, 1) with nowait'
set #cmd3 = 'if ''?'' like ''commonprefix_%'' print ''Finished ?'''
set #cmd2 =
replace('if ''?'' like ''commonprefix_%''
begin
use [?]
{0}
end', '{0}', #sql)
exec sp_msforeachdb #command1 = #cmd1, #command2 = #cmd2, #command3 = #cmd3
The nice thing about this is all you have to do is set the #sql variable to your query text. Very easy to turn into a stored procedure. It's dynamic sql, but again: it's only used for development (famous last words ;) ). The downside is that you still need to escape single quotes used in the query and much of the time you'll end up putting an extra ''?'' As ClientDB column in the select list, but otherwise it works well enough.
Unless I get another really good idea today I want to turn this into a stored procedure and also put together a version as a table-valued function using a temp table to put all the results in one resultset (for select queries only).
Just wrap the statement you want to execute in an IF NOT IN:
EXEC sp_msforeachdb "
IF '?' NOT IN ('DBs','to','exclude') BEGIN
EXEC sp_whatever_you_want_to
END
"
Each of our database servers contains a "DBA" database that contains tables full of meta-data like this.
A "databases" table would keep a list of all databases on the server, and you could put flag columns to indicate database status (live, archive, system, etc).
Then the first thing your SCRIPT does is to go to your DBA database to get the list of all databases it should be running against.
We even have a nightly maintenance script that makes sure all databases physically on the server are also entered into our "DBA.databases" table, and alerts us if they are not. (Because adding a row to this table should be a manual process)
How about taking the definition of sp_msforeachdb, and tweaking it to fit your purpose? To get the definition you can run this (hit ctrl-T first to put the results pane into Text mode):
sp_helptext sp_msforeachdb
Obviously you would want to create your own version of this sproc rather than overwriting the original ;o)
Doing this type of thing is pretty simple in 2005 SSIS packages. Perhaps you could get an instance set up on a server somewhere.
We have multiple servers set up, so we have a table that denotes what servers will be surveyed. We then pull back, among other things, a list of all databases. This is used for backup scripts.
You could maintain this list of databases and add a few fields for your own purposes. You could have another package or step, depending on how you decide which databases to report on and if it could be done programmatically.
You can get code here for free: http://www.sqlmag.com/Articles/ArticleID/97840/97840.html?Ad=1
We based our system on this code.

Categories

Resources