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
Related
We recently moved a database to it's own SQL Server which broke a call to a stored proc wrapped in a sp_cursoropen statement.
The original call, which worked, was to a database on the same server as the calling database:
using database1
exec sp_cursoropen #p1 output, N'exec database2.dbo.sp_mystoredproc 1234'
We had to move the second database to its own server for compliance reasons and created a linked server between the two. We changed the call to:
using database1
exec sp_cursoropen #p1 output, N'exec LinkedDBServer.database2.dbo.sp_mystoredproc 1234'
The call no longer works and gives us two errors
A server cursor cannot be opened on the given statement or statements. Use a default result set or client cursor.
The cursor was not declared
The funny thing is that running the stored proc command on it's own works and returns rows of data:
using database1
exec LinkedDBServer1.database2.dbo.sp_mystoredproc 1234
Also funny, putting direct SQL from the stored proc itself and pasting it in place of sp_mystoredproc also works, even with the cursor:
using database1
exec sp_cursoropen #p1 output, N'Select * from LinkedDBServer1.Dbname.dbo.sometable where sometable.id = 1234'
This leads me to believe that the return type of the stored procedure that runs via a linked server is somehow different than that of the same stored procedure running on the same SQL server as the calling database. Unfortunately, I cannot find any documentation to support my hypothesis.
Does anyone know why a stored procedure that returns rows of data wouldn't play well with sp_cursoropen when a linked server is involved?
Note: I'm not interested in workarounds. I know there are many ways to fix this such as writing to a temp table first, using a different service to grab the data or some other method of completing the task. I'm only interested in what low level difference in the SQL server is causing this error even though the separate pieces being called to through the linked server work independently.
I've got a database that is replicated on two servers, a live server and a test server, so that whenever it's needed the 'test' database gets overwritten by the 'live' database (so that I can reset everything if I've made a mess.)
I want an Stored Procedure in the 'test' database, that will only run in the 'test' database, but to do this I need to have it in the 'live' database as well, so that it can be copied over when 'test' is overwritten.
The procedure starts:
if ##SERVERNAME<>'TEST'
begin
raiserror ('NOT ON TEST! This SP must only be run on TEST.',16,1)
return
end
So that if it runs in live, it immediately exits.
Unfortunately the "Live" database server uses an older version of SQL, and doesn't seem to understand the lead/lag/over statements in the script, and refuses to create the procedure because of these "Incorrect syntax" errors.
The SP definitely works in the test server.
Is there a way to disregard the error messages when creating a stored procedure?
I've found a prior question that explained how to make a stored procedure with the same name, but I need the stored procedure to contain the script that the server thinks is incorrect.
The only way to not get the stored-procedure validated when created, is to run a dynamic-sql query within.
Example:
CREATE PROCEDURE dbo.YourStoredProcedure AS
BEGIN
IF ##SERVERNAME<>'TEST'
BEGIN
RAISERROR ('NOT ON TEST! This SP must only be run on TEST.',16,1)
RETURN
END
DECLARE #SQL NVARCHAR = N'
SELECT rowOne
, rowTwo
, valueOne
, LEAD(valueOne) OVER (PARTITION BY rowOne ORDER BY rowTwo DESC) AS preValue
FROM dbo.YourTable
'
EXEC(#SQL)
END
Notes:
On the long term, try to find a better strategy than DB replication for different systems. Check Continuous Deployment
Make sure to check concatenated dynamic-sql for potential issues (sql injection). Check QUOTENAME()
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.
If I understand correctly, with stored procedure result is also returned a message called DONE_IN_PROC
Fragment From MSDN:
... SET NOCOUNT ON eliminates the sending of DONE_IN_PROC messages to the
client for each statement in a stored procedure.
Is there a way to access this message somehow in Management Studio after executing stored procedure and read i.e. number of rows affected.
(I am asking out of curiosity and I know there are other ways to get number of rows affected)
Certain (if not all) Database APIs make the TDS layer's DONE_IN_PROC message accessible. If ODBC is the chosen Database API, see the http://technet.microsoft.com/en-us/library/ms130812.aspx discussion about SQLRowCount, SQLGetStmtAttr, and NOCOUNT.
Late to the party but are you just after the int from the message?
create proc delme as
begin
select * from sys.databases
end
go
set nocount on
go
exec delme --returns "(7 row(s) affected)" on the message channel
select ##ROWCOUNT --returns 7
I am investigating an odd error from a SQL Server 2005 stored procedure which I cannot reproduce by calling it directly from Management Studio.
Therefore I'd like to be able to:
set a breakpoint in the stored procedure
wait for the procedure to be called externally and the breakpoint hit
see the values of the passed-in parameters
step through the stored procedure
Is this possible, and if so how?
You could try the "server explorer" from visual studio but the sqlserver needs to be configured to allow debugging. Here is some info: https://web.archive.org/web/20211020102846/https://www.4guysfromrolla.com/articles/051607-1.aspx. But I think that you first should try Profiler like Eppz say. :)
Use SQL Profiler to view what is happening when the procedure gets called and what params are passed in.
If you can't step through the code, here are two ways:
#1 concatenate a string, and insert into a log file.
Declare a variable like:
DECLARE #Loginfo varchar(7500)
append debug info into it as you progress through the code:
SET #LogInfo=ISNULL(#LogInfo)+'#01> #x='+COALESCE(CONVERT(varchar(10),#x),'NULL')
..
SET #LogInfo=ISNULL(#LogInfo)+'#02>'
..
SET #LogInfo=ISNULL(#LogInfo)+'#03> top loop'
at all exit points (after any rollbacks) add:
INSERT INTO YourLogTable VALUES (... ,#LogInfo )
depending on the transaction usage and you error in particular, you may be able to just insert many times with no fear of rollback, so you will need change this to your situation.
#2 write to a text file on the sq server
this may not be an option because it uses the very insecure xp_cmdshell stored procedure. However, if you can use that and if transactions from the calling app are causing a problem try creating this stored procedure:
CREATE PROC log_message
#Message varchar(255)
,#FileName varchar(100)
,#OverWrite char(1) = 'N'
AS
/*
Log messages to server side text files from stored procedures/triggers/sql scripts
Input parameters:
Message - message to put in the log file
FileName - path and name of the file to log the message into
OverWrite - 'Y'=overwrite entire file with current message
'N'=append current message onto end of file
Return code:
0 - everything was fine
1 - there was an error
NOTE: the command to log the message can not be longer than 255 characters,
as a result the message and file name should be less than 245 chars combined
Example: EXEC log_message 'Duplicates found','C:\logfile.txt', 'N'
append the "Duplicates found" message onto the server's "C:\logfile.txt" file
*/
BEGIN
SET NOCOUNT ON
DECLARE #ExecuteString VARCHAR(255) --command string can only be 255 chars long
DECLARE #ReturnValue int
--build command string
SET #ExecuteString = RTRIM('echo ' + COALESCE(LTRIM(#Message),'-')
+ CASE WHEN (#OverWrite = 'Y') THEN ' > ' ELSE ' >> ' END + RTRIM(#FileName))
--run command string
EXEC #ReturnValue=master..xp_cmdshell #ExecuteString
--IF #ReturnValue!=0
-- PRINT 'command failed, return value='+CONVERT(varchar(40),#ReturnValue)
RETURN #ReturnValue
SET NOCOUNT OFF
END
sprinkle calls to this procedure these through your code write what you need into a file on the server
Update: I am not sure if there is a way to attach to a running stored proc. You can use profiler to get a real time trace of the statements getting executed (SP:StmtStarting). Also check out Apex SQL Debug which seems to have more capabilities and is available as an Add-in to Management Studio.
If you have Visual Studio, it is easy to debug:
Debugging Stored Procedures in Visual Studio 2005
More answers here:
What’s your favored method for debugging MS SQL stored procedures?
I would use a combination of SQL Profiler and print statements inside of your SQL statement. Not sure of a way to step thru line by line but using profiler in combination with print and select statements (if using temp tables) to view their contents as the proc runs will quickly shed light on what's happening.