I need to surpress messages output from a SQL function. As in 1 row affected. I can't use SET NOCOUNT as it's invalid in a function.
Anyone know a way to do this?
Thanks.
EDIT
I was trying to limit the background information in an attemp to boil the problem down to it's essence. But I'll expand. I'm using MSSQL2005 and NHibernate to insert a record in to a SQL table. On the table I have a computed column that runs the function which is reporting back 1 row affected.
I didn't really want to edit the NHibernate part of the process but it may be unavoidable.
A function that returns "(1 row affected)" will be part of a bigger query in a batch. It makes no sense to have SET NOCOUNT ON in the function
You need to do this:
SET NOCOUNT ON;
SELECT * FROM MyUDFTVF();
Note a stored procedure is simply a wrapper for this
CREATE PROC Whatever
AS
SET NOCOUNT ON;
SELECT * FROM MyUDFTVF();
GO
SET NOCOUNT ON is normally needed to stop triggers etc breaking client code: why do you need it here?
The nocount setting is not available in functions.
Stored procedures allow you to set nocount. So converting the function to a stored procedure would solve the problem.
Otherwise, the calling code will have to set nocount. That shouldn't be hard, but might be tedious if the function is used in many places.
P.S. If you post the reason why suppressing the count messages is required, perhaps we can offer some more solutions.
Related
I want to insert the results of a stored procedure into a temp table using OPENROWSET. However, the issue I run into is I'm not able to pass parameters to my stored procedure.
This is my stored procedure:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[N_spRetrieveStatement]
#PeopleCodeId nvarchar(10),
#StatementNumber int
AS
SET NOCOUNT ON
DECLARE #PersonId int
SELECT #PersonId = [dbo].[fnGetPersonId](#PeopleCodeId)
SELECT *
INTO #tempSpRetrieveStatement
FROM OPENROWSET('SQLNCLI', 'Server=PCPRODDB01;Trusted_Connection=yes;',
'EXEC Campus.dbo.spRetrieveStatement #StatementNumber, #PersonId');
--2577, 15084
SELECT *
FROM #tempSpRetrieveStatement;
OpenRowSet will not allow you to execute Procedure with input parameters. You have to use INSERT/EXEC.
INTO #tempSpRetrieveStatement(Col1, Col2,...)
EXEC PCPRODDB01.Campus.dbo.spRetrieveStatement #StatementNumber, #PersonId
Create and test a LinkedServer for PCPRODDB01 before running the above command.
The root of your problem is that you don't actually have parameters inside your statement that you're transmitting to the remote server you're connecting to, given the code sample you provided. Even if it was the very same machine you were connecting to, they'd be in different processes, and the other process doesn't have access to your session variables.
LinkedServer was mentioned as an option, and my understanding is that's the preferred option. However in practice that's not always available due to local quirks in tech or organizational constraints. It happens.
But there is a way to do this.
It's hiding in plain sight.
You need to pass literals into the string that will be executed on the other server, right?
So, you start by building the string that will do that.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[N_spRetrieveStatement]
#PeopleCodeId nvarchar(10),
#StatementNumber int
AS
SET NOCOUNT ON
DECLARE
#PersonId INT,
#TempSQL VARCHAR(4000) = '';
SELECT #PersonId = [dbo].[fnGetPersonId](#PeopleCodeId);
SET #TempSQL =
'EXEC Campus.dbo.spRetrieveStatement(''''' +
FORMAT(#StatementNumber,'D') +''''', ''''' +
FORMAT(#PersonId,'D') + ''''')';
--2577, 15084
Note the seemingly excessive number of quotes. That's not a mistake -- that's foreshadowing. Because, yes, OPENROWSET hates taking variables as parameters. It, too, only wants literals. So, how do we give OPENROWSET what it needs?
We create a string that is the entire statement, no variables of any kind. And we execute that.
SET #TempSQL =
'SELECT * INTO #tempSpRetrieveStatement ' +
'FROM OPENROWSET(''SQLNCLI'', ''Server=PCPRODDB01;Trusted_Connection=yes;'', ' + #TempSQL +
'EXEC Campus.dbo.spRetrieveStatement #StatementNumber, #PersonId';
EXEC (#TempSQL);
SELECT *
FROM #tempSpRetrieveStatement;
And that's it! Pretty simple except for counting your escaped quotes, right?
Now... This is almost beyond the scope of the question you asked, but it is a 'gotcha' I've experienced in executing stored procedures in another machine via OPENROWSET. You're obviously used to using temp tables. This will fail if the stored procedure you're calling is creating temp tables or doing a few other things that -- in a nutshell -- inspire the terror of ambiguity into your SQL server. It doesn't like ambiguity. If that's the case, you'll see a message like this:
"Msg 11514, Level 16, State 1, Procedure sp_describe_first_result_set, Line 1
The metadata could not be determined because statement '…your remote EXEC statement here…' in procedure '…name of your local stored procedure here…' contains dynamic SQL. Consider using the WITH RESULT SETS clause to explicitly describe the result set."
So, what's up with that?
You don't just get data back with OPENROWSET. The local and remote servers have a short conversation about what exactly the local server is going to expect from the remote server (so it can optimize receiving and processing it as it comes in -- something that's extremely important for large rowsets). Starting with SQL Server 2012, sp_describe_first_result_set is the newer procedure for this, and normally it executes quickly without you noticing it. It's just that it's powers of divination aren't unlimited. Namely, it doesn't know how to get the type and name information regarding temp tables (and probably a few other things it can't do -- PIVOT in a select statement is probably right out).
I specifically wanted to be sure to point this out because of your reply regarding your hesitation about using LinkedServer. In fact, the very same reasons you're hesitant are likely to render that error message's suggestion completely useless -- you can't even predict what columns you're getting and in what order until you've got them.
I think what you're doing will work if, say, you're just branching upstream based on conditional statements and are executing one of several potential SELECT statements. I think it will work if you're just not confident that you can depend on the upstream component being fixed and are trying to ensure that even if it varies, this procedure doesn't have to because it's very generic.
But on the other hand you're facing a situation in which you literally cannot guarantee that SQL Server can predict the columns, you're likely going to have to force some changes in the stored procedure you're calling to insist that it's stable. You might, for instance work out how to ensure all possible fields are always present by using CASE expressions rather than any PIVOT. You might create a session table that's dedicated to housing what you need to SELECT just long enough to do that then DELETE the contents back out of there. You might change the way in which you transmit your data such that it's basically gone through the equivalent of UNPIVOT. And after all that extra work, maybe it'll be just a matter of preference if you use LinkedServer or OPENROWSET to port the data across.
So that's the answer to the literal question you asked, and one of the limits on what you can do with the answer.
What is the Oracle equivalent of SQL Server's SET NOCOUNT ON?
From the SQL Server documentation:
SET NOCOUNT ON... Stops the message that shows the count of the number of rows affected by a Transact-SQL statement or stored procedure from being returned as part of the result set...
For stored procedures that contain several statements that do not return much actual data, or for procedures that contain Transact-SQL loops, setting SET NOCOUNT to ON can provide a significant performance boost, because network traffic is greatly reduced.
There is no equivalent in Oracle when set nocount on is used inside a stored procedure, simply because it's not necessary to do (inside a procedure or function).
The only vaguely matching thing is set feedback off as mentioned by BigMike
SET FEEDBACK OFF at SQL*plus prompt.
For official docs please refer to this
I have many procedures that has set nocount on.
Is it necessary to turn it off at the end of stored procedure?
e.g.:
create procedure DummyProc
as
begin
set nocount on
...
set nocount off
end
set nocount on will disable the X rows affected. message SQL returns. This message is suppressed, in some cases, due to undesired effects with the client executing the stored proc.
set nocount off will undo this suppression. However, set nocount on is a scope setting, and by default, will be turned off when leaving the scope anyway.
Now, is set nocount off necessary? No, as any new commands executed will be in a different scope, and by default set nocount off is always in effect. But as stated above in comments, it's considered a good practice, just to explicitly indicate that this setting will return to normal when the proc is finished executing.
I know this is a rather old post but it was the first hit on Google when I looked for the answer. The response above to test it was a very good idea.
I tested this out and wanted to update the above with some additional details.
The scope you create with a SET NOCOUNT ON flows to any procs which your procedure calls. So if your procedure does SET NOCOUNT ON and then you call a sproc, that sproc gets your SET NOCOUNT setting. The setting DOES go away when you exit your sproc but the setting flows down into called sprocs. If you SET NOCOUNT inside of the CALLED sproc, the outer sproc will have the SET NOCOUNT which it set and the inner sproc won't affect the outer sproc.
So I think you don't really need to reset it at the end of your sproc because your settings will never flow OUT of your sproc upwards; however, if your sproc depends on the setting, it should set it before it needs it because if it gets called from another sproc, it could have a different setting than you assume.
only if you dont want to see
(1 row(s) affected) // or n rows....
most of the time - when you debug
and you use print command - so you want to see pure text of your own... so thats a good practice.
edit
it does Not affect your query result (on or off - it doesn't matter.)- if thats what's your asking. ( thanks JNK).
its simple. you dont need it if another program is running your procedure.
Lets say my python code is calling an mssql procedure, then I don't need the affected row count on my app, so I "SHOULD" definitely put "set nocount on" in my code
We have introduced a new data access framework for calling SQL Stored procedures. When calling a stored procedure that returns a recordset, we've run into problems where that stored procedure also performs an update (insert/update/delete) of some sort:
Cannot change the ActiveConnection
property of a Recordset object which
has a Command object as its source.
The solution to this is to add 'SET NOCOUNT ON' to the top of the stored procedure. This works just fine, and, of course, it also has a touted performance enhancement.
We are recommending to developers that when they want to write code to call an existing stored procedure, they must also refactor the stored procedure itself to include SET NOCOUNT ON.
But, this got me into wondering, what would be the potential consequences/risks of performing a blanket update of all stored procedures to include SET NOCOUNT ON. Under what scenarios would this break an SPs functionality? (given that ##ROWCOUNT function is updated even when SET NOCOUNT is ON)
Help, as always, much appreciated.
I think the main danger would be if any of your existing processes look for and/or assume that the rowcount will be returned without explicitly querying the value of ##ROWCOUNT.
It's possible that somewhere in your code is a stored proc that gets executed, and the application waits for the return row value to know that it completed, in which case the app would hang indefinitely.
I am creating a stored procedure in Sql Server 2008 database. I want to return the number of rows affected. Which is a better option SET NOCOUNT OFF or RETURN ##ROWCOUNT?
ALTER PROCEDURE [dbo].[MembersActivateAccount]
#MemberId uniqueidentifier
AS
BEGIN
-- Should I use this?
SET NOCOUNT OFF;
UPDATE [dbo].Members SET accountActive = 1 WHERE id = #MemberId;
--Or should I SET NOCOUNT ON and use the following line instead?
--return ##ROWCOUNT;
END
I know that both work, but which is a better choice and why?
After some trying I am coming to a conclusion that SET NOCOUNT is OFF by default inside stored procedures. Is it possible to change this behavior inside my database?
Use ##RowCount. It's explicit and transparent, it is entirely controlled by your code rather than a built-in behaviour.
The NOCOUNT option can be manually set to default to ON (Optons>Query Execution>SQL Server>Advanced). If you set it this way but then declare SET NOCOUNT OFF in your stored procedure then that local setting takes precedence.
Don't use RETURN for values. By convention RETURN from stored procedures is for error codes, 0 meaning no error and non-0 meaning some kind of problem. If you need data back, the appropriate way to do it is with an OUTPUT parameter. It's a little counter-intuitive based on other languages' use of return.
I know that having SET NOCOUNT ON would make a DataAdapter think there was a concurrency conflict.
You can read about it on MSDN. If the code is going to be used by DataAdapters then obviously don't use SET NOCOUNT ON.
It looks like SqlCommand also has this behaviour, which I guess is the reason why the DataAdapter has a problem (as under the hood it will use a Command object).
Reasons for using SET NOCOUNT ON/OFF:
To control the stack overflow while inserting rows into any table.
Passing the T-Sql messages while executing of the queries or nested queries.
To Show or viewing the latest queries executed.
To get information on the latest record escalation.
Why we use SET NOCOUNT on/off ---
Ans : we can understand this by following steps
step 1 : execute query "Select top 10 * from table name".
step 2 : open message window it shows a message "10 rows affected". it creates extra overheads and extends our execution time.
step 3 : to overcome this extra overheads we use SET NOCOUNT ON. If it is On then it will never count the number of row returns instead it sows a message commands completed successfully.
step 4 : By default NOCOUNT is ON then it counts the number of returned rows that is why my suggestion that it should off during creating new procedures to get better performance from database server.