Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does @@ROWCOUNT return 1 for a NULL statement using sp_executesql?

If I run this:

DECLARE @sql NVARCHAR(10) = NULL;
EXEC sp_executesql @sql;
SELECT @@ROWCOUNT;

I would expect to get 0, maybe even NULL would make sense. But I don't get either, I get 1. Why is 1 row affected by executing a NULL query? If I pass in a "proper" (non_NULL) query then it works fine.


Background (for those that care): this is from a process that is supposed to generate some dynamic SQL to update one row and ONLY one row. I need to check that 1 row has been affected, not 0 or 2 or more than 2. It worked fine until somehow a NULL SQL statement managed to be generated, and this was seen as a success - oops!

The actual fix will be to check the SQL is non-NULL before running it, and treat a NULL statement the same way as a result other than 1. But I was still curious why it behaved this way.

like image 717
Richard Hansell Avatar asked Jul 01 '19 15:07

Richard Hansell


People also ask

What is rowcount_big in SQL Server 2014?

Applies to: SQL Server (all supported versions) Azure SQL Database Azure SQL Managed Instance Returns the number of rows affected by the last statement. If the number of rows is more than 2 billion, use ROWCOUNT_BIG. To view Transact-SQL syntax for SQL Server 2014 and earlier, see Previous versions documentation.

How do I set the value in @@rowcount in Transact-SQL?

Transact-SQL statements can set the value in @@ROWCOUNT in the following ways: Set @@ROWCOUNT to the number of rows affected or read. Rows may or may not be sent to the client. Preserve @@ROWCOUNT from the previous statement execution.

How do I reset the rowcount value to 0?

DECLARE CURSOR and FETCH set the @@ROWCOUNT value to 1. EXECUTE statements preserve the previous @@ROWCOUNT. Statements such as USE, SET <option>, DEALLOCATE CURSOR, CLOSE CURSOR, PRINT, RAISERROR, BEGIN TRANSACTION, or COMMIT TRANSACTION reset the ROWCOUNT value to 0. Natively compiled stored procedures preserve the previous @@ROWCOUNT.

What is the use of the output parameter in SP_ExecuteSQL?

sp_executesql provides to return execution result of the dynamically constructed SQL statement or batch. The OUTPUT parameter plays a key role to resolve this case. In this example, we will count the row number of the PersonPhone table and then we will set the return value to a variable with the OUTPUT parameter.


2 Answers

It's because you're assign NULL to your variable. Statements that make a simple assignment always set the @@ROWCOUNT value to 1.

See the example below. Because management studio can run its own queries on the connection and mess with the @@ROWCOUNT value it starts off selecting an empty result set to ensure the initial @@ROWCOUNT value is zero.

When there is no assignment the SELECT @@ROWCOUNT returns 0 (the initial value has not been modified). Otherwise it returns 1

/*Ensure @@ROWCOUNT starts off at 0*/
SELECT 1 WHERE 1 = 0;

DECLARE @sql NVARCHAR(10);
EXEC sp_executesql @sql;
SELECT @@ROWCOUNT;

GO

/*Ensure @@ROWCOUNT starts off at 0*/
SELECT 1 WHERE 1 = 0;

DECLARE @sql NVARCHAR(10) = NULL;
EXEC sp_executesql @sql;
SELECT @@ROWCOUNT;

You can also try similar with a non zero initial value:

/*Ensure @@ROWCOUNT starts off at 3*/
SELECT 1 UNION SELECT 2 UNION SELECT 3

DECLARE @sql NVARCHAR(10);
EXEC sp_executesql @sql;
SELECT @@ROWCOUNT; --Returns 3

GO

/*Ensure @@ROWCOUNT starts off at 3*/
SELECT 1 UNION SELECT 2 UNION SELECT 3

DECLARE @sql NVARCHAR(10) = NULL;
EXEC sp_executesql @sql;
SELECT @@ROWCOUNT; --Returns 1
like image 184
Ilyes Avatar answered Sep 26 '22 03:09

Ilyes


Please note that my answer was written purely from my experience of SQL Server Management Studio and does not accurately explain this behaviour. Martin Smith has explained why this isn't true in a comment below.

It looks like sp_executesql doesn't run at all with a null parameter, perhaps as a failsafe.

Try running "SELECT @@ROWCOUNT" alone in a batch and you'll see that it returns 1, regardless of the fact there is no current rowcount. It seems likely that 1 is the default return value and that's why you're seeing this.

like image 44
reembank Avatar answered Sep 26 '22 03:09

reembank