Problems with data providers and SET NOCOUNTIts standard good practise to always use
SET NOCOUNT ON in your
stored procedures to prevent system messages about the number of rows affected by
DML statements from being returned. However as well as being good practise I have found that it can actually cause issues in certain cases depending on the
data access provider used to connect to your
SQL database from your front end application. If you have read my article about
migrating from 32 bit to 64 bit applications you will see that I mention certain issues there. I have experienced problems when moving from
MDAC to
SQLOLEDB when stored procedures contain multiple
DML statements and
SET NOCOUNT has not been set as it seems these system messages are being returned as a recordset and whereas
MDAC will ignore them
SQLOLEDB doesn't. Therefore you may experience errors such as "
Operation not allowed when the object is closed" or "
item or ordinal does not exist in collection" because these system messages are being returned or accessed before your intended recordset is.
Solution - Add SET NOCOUNT ONTherefore the solution is simple, make sure all
stored procedures have this command set at the top of them. However if you have a large database containing hundreds of stored procedures then this would be quite a task to carry out manually. Therefore I came up with a way to automate this task when upgrading large database systems by using the
system views available in
SQL Server.The idea is pretty simple.
- Find out which stored procedures do not contain the SET NOCOUNT statement.
- Script out those stored procedures and update them to contain the statement.
- Run the script to ALTER the stored procs and update the database
- Use standard functions and pure TSQL to accomplish the task.
Syscomments and SysobjectsIn
SQL 2000 and
2005 all
stored procedure and user defined functions have their source code available for viewing from the
syscomments system view. The
system views cannot be updated directly so its a case of using them to generate
ALTER statements to run if anything requires changing.
You can view all the
stored procedures without the
SET NOCOUNT statement with the following
SQL.
SELECT c.*,o.*
FROM sys.syscomments as c
JOIN sys.sysobjects as o
ON o.id = c.id
WHERE xtype='P' --stored procs
AND Name LIKE 'usp_%' --my prefix
AND LOWER(text) NOT LIKE '%set nocount on%'
ORDER BY o.Name
One of the things you should be aware of is that the text column which contains the code is
nvarchar(4000) and procedures or functions that have a code length greater than 4000 will be split up over multiple rows. The
id column relates to the system
object_id which can be used to join to
sysobjects and the
colid will contain the subsection of code. Therefore you will notice that the previous SQL is not 100% correct as a procedure that is split over 4 rows maybe returned even if it does have
SET NOCOUNT ON set because only the first section with a
colid of 1 will not match the filter.
Solution to the problemThe final script I used to solve this solution can be accessed here:
Download SQL script to insert missing SET NOCOUNT ON statements to stored proceduresI have split it into two separate loops mainly to get round limitations of displaying large strings from variables in
query analyser and the
system stored procedure I have used to return the complete code from
syscomments which is called
sp_helpText. There are multiple ways that this task could have been achieved but I wanted to keep it a
purely TSQL solution and although its not the most elegant piece of code ever writen it has done the job it was designed to do which was to update 100+
stored procedures so that I didn't have to do it by hand.
To view more solutions to common
database problems that I have solved by using the
system views please see