We use the @@Error and @@rowcount system variables all the time in queries and sprocs. However, one might be lead astray thinking they behaved like “regular” variables in programming, i.e., they are persistent, but they are not, they only hold the value from the most recent statement.
Here’s an example where I declare a couple of variables to hold the error and rowcount values and purposely create an illegal query (division by zero), then I grab the rowcount in one statement and display that plus the “error” in the next. Note that the no error value is zero and a non-zero value indicates error:
declare @Error int, @rowcount int
select @Error = 0, @rowcount = 0
select ‘Query 1/0′ = 1/0
select @rowcount = @@rowcount
select ‘@@Error‘ = @@Error, ‘@rowcount’ = @rowcount
The results are this:
Query 1/0
———–
Msg 8134, Level 16, State 1, Line 5
Divide by zero error encountered.
@@Error @rowcount
———– ———–
0 1
Huh? How come the @@Error value is still zero? The real error value was overwritten by the “error” value from the statement “select @rowcount = @@rowcount”, which of course will always be successful. Here’s how to properly capture the error and rowcount:
declare @Error int, @rowcount int
select @Error = 0, @rowcount = 0
select ‘Query 1/0′ = 1/0
select @Error = @@Error, @rowcount = @@rowcount
select ‘@Error’ = @Error, ‘@rowcount’ = @rowcount
and here’s the correct results:
Query 1/0
———–
Msg 8134, Level 16, State 1, Line 4
Divide by zero error encountered.
@Error @rowcount
———– ———–
8134 1
So the last piece is, why is rowcount still 1 when no data rows were returned? Every select statement that doesn’t hit an actual table returns at least one row. If we rem out all of the select and set statements then we get a zero for rowcount.:
declare @Error int, @rowcount int
–select @Error = 0, @rowcount = 0
–select ‘Query 1/0′ = 1/0
select @Error = @@Error, @rowcount = @@rowcount
select ‘@Error’ = @Error, ‘@rowcount’ = @rowcount
results:
@Error @rowcount
———– ———–
0 0
So when we do hit a real table, we’ll get an accurate capture of row count activity:
declare @Error int, @rowcount int
select @Error = 0, @rowcount = 0
select id, status from master..sysobjects where name = ‘grumpy’
select @Error = @@Error, @rowcount = @@rowcount
select ‘@Error’ = @Error, ‘@rowcount’ = @rowcount
results (obviously, no table in master with a name of grumpy):
id status
———– ———–
@Error @rowcount
———– ———–
0 0
And one that returns data:
declare @Error int, @rowcount int
select @Error = 0, @rowcount = 0
select id, status from master..sysobjects where name = ‘sysindexes‘
select @Error = @@Error, @rowcount = @@rowcount
select ‘@Error’ = @Error, ‘@rowcount’ = @rowcount
results (one data row, no errors):
id status
———– ———–
-134 0
@Error @rowcount
———– ———–
0 1
These behaviors are predictable and repeatable and form the basis of structured error handling in sprocs in SQL 2000. For SQL2005, we have the beautiful new Try/Catch model for error management that makes life a breeze.