Handling NULL results

Prior to release 11.0, a correlated expression subquery in the set clause of an update returned 0 instead of NULL when there were no matching rows. Release 11.0 correctly returns NULL when there are no matching rows, and an error is raised if the column does not permit nulls.

If you have applications that depend on the pre-release 11.0 behavior, you will need to rewrite them.

For example, the following trigger tries to update a column that does not permit NULL values:

update t1
     set c1 = (select max(c1) 
     from inserted where t1.c2 = inserted.c2)

The correct trigger is:

update t1
     set c1 = (select isnull(max(c1), 0)
     from inserted
     where t1.c2 = inserted.c2)

or:

update t1
     set c1 = (select max(c1)
     from inserted
     where t1.c2 = inserted.c2)
 where exists (select * from inserted 
     where t1.c2 = inserted.c2)

The where clause updates table t1.c1 to 0, if the subquery does not return any correlation values from the outer table t1.

Another example of this is the totalsales_trig in the pubs2 sample database. In previous versions, the trigger read as follows:

create trigger totalsales_trig
 on salesdetail
 for insert, update, delete
 as
 /* Save processing:  return if there are no rows affected */
 if @@rowcount = 0
         begin
                 return
         end
  
 /* add all the new values */
 /* use isnull:  a null value in the titles table means 
 **              “no sales yet” not “sales unknown”
 */
 update titles
         set total_sales = isnull(total_sales, 0) + 
         (select sum(qty)
                 from inserted
                 where titles.title_id = inserted.title_id)
  
 /* remove all values being deleted or updated */
 update titles
         set total_sales = isnull(total_sales, 0) - 
         (select sum(qty)
                 from deleted
                 where titles.title_id = deleted.title_id)

sum(qty) is NULL if no row is returned from the table, so when a statement changes the total_sales column, the trigger changes to NULL all the rows in titles that do not qualify.

To guarantee that the subquery in the expression for the update returns a non-null value, the corrected trigger is:

create trigger totalsales_trig
 on salesdetail
 for insert, update, delete
 as
 /* Save processing:  return if there are no rows affected */
 if @@rowcount = 0
         begin
                 return
         end
  
 /* add all the new values */
 /* use isnull:  a null value in the titles table means 
 **              “no sales yet” not “sales unknown”
 */
 update titles
         set total_sales = isnull(total_sales, 0) + 
         (select sum(qty)
                 from inserted
                 where titles.title_id = inserted.title_id)
         where title_id in (select title_id from inserted)
 
 /* remove all values being deleted or updated */
 update titles
         set total_sales = isnull(total_sales, 0) - 
         (select sum(qty)
                 from deleted
                 where titles.title_id = deleted.title_id)
         where title_id in (select title_id from deleted)