Skip to Main Content
  • Questions
  • how to handle no data found in a complicated update

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question, Nag.

Asked: October 30, 2001 - 10:59 am UTC

Last updated: August 28, 2006 - 10:55 am UTC

Version: 8.1.7

Viewed 1000+ times

You Asked


I have an update statement like this

for rec in c5

loop
Update t

set t.col1=(select t.co1+t1.col1
where t.key=t1.key
and t.1.id=(select id from t3
where t3.dt= somedate and
t3.col6=rec.col6..........)),
t.col2=select t.co1+t1.col1
where t.key=t1.key
and t.1.id=(select id from t3
where t3.dt= somedate....
t3.col6=rec.col6..........))
where t.col3 =something
t.col4=something .

end loop;

Tom

My questions are

How should we handle a no data found returned by the inner most query.
Will the no data found in the inner most query , will result in the failing of the whole update statement.

In the innermost query can use the rec.col6 value as I have used above.

thank you

and Tom said...

There will be no "no data found" raised during this query.

ops$tkyte@ORA8I.WORLD> insert into t values ( 1 );

1 row created.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> update t set x = ( select y from t2 where y in ( select y from t2 ) );

1 row updated.

ops$tkyte@ORA8I.WORLD> select * from t;

X
----------


ops$tkyte@ORA8I.WORLD>

It'll be set to NULL. If this is not what you want -- you need to add a where exists to your where clause:

ops$tkyte@ORA8I.WORLD> insert into t values ( 1 );

1 row created.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> update t set x = ( select y from t2 where y in ( select y from t2 ) )
2 where exists ( select y from t2 where y in ( select y from t2 ) );

0 rows updated.

ops$tkyte@ORA8I.WORLD> select * from t;

X
----------
1

to catch and ignore rows where the subquery returns 0 records.

Rating

  (7 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

Let me rewrite it according to your guidelines ....

Nag, October 30, 2001 - 12:10 pm UTC

I am updating the table t, to update the prices , so a null will not be acceptable to me, so let me rewrite the update accoridng to your advise.

Update t

set t.col1=(select t.co1+t1.col1
where t.key=t1.key
and t.1.id=(select id from t3
where t3.dt= somedate and
t3.col6=rec.col6..........)),
t.col2=select t.co1+t1.col1
where t.key=t1.key
and t.1.id=(select id from t3
where t3.dt= somedate....
t3.col6=rec.col6..........))
where t.col3 =something and
t.col4=something and
exists( select id from t3
where t3.dt= somedate and
t3.col6=rec.col6..........)

I added the exists to the end with the innermost subquery as you have suggested in your example.

1.But please not that , Iam updating 2 columns, and the inner most subquery differs for both of them to the effec taht the t3.dt= somedate will differ. Now which one of these inner most subqueries should go into the exists clause.

2.Actually, how is the exists clause helping us in avoiding a null

(It could have been ideal had you given an example updating 2 columns, and updating the columns by adding to the updating columns in the update.)




Tom Kyte
October 30, 2001 - 1:07 pm UTC

You cannot just do the innermost subquery. Your syntax is incomplete, the example won't run. (and you shouldn't use somedate two TIMES if they are different, use something like "somedate_1" "somedate_2" else they sure look the same to me.

Whether you have 1 or 100 columns to update, it'll be the same:

update t
set c1 = ( subquery1 ),
...
cn = ( subqueryN )
where <your conditions>
and exists (subquery1)
...
and exists (subqueryN)


Just copy the subqueries into the where clause in total.


You are awesome- you solved the mystery for me

Nag, October 30, 2001 - 1:15 pm UTC


1.Actually, how is the exists clause helping us in avoiding a null.

2.Is this kind of an update given else where on your websidte , and in oracle documentation


Tom Kyte
October 30, 2001 - 1:28 pm UTC

1) if the exists is not satisified, you won't update the row. Hence, it won't update it to null.

2) it is a natural thing, very common yes.

see
</code> http://asktom.oracle.com/pls/asktom/f?p=100:11:::::P11_QUESTION_ID:288016031632 <code>

where exists is just a predicate -- you can use it in any where clause. The doc for UPDATE does show something very similar only they used an IN instead of WHERE EXISTS.

update to zero when null

Nag, October 30, 2001 - 2:55 pm UTC

my objective is to update the column x in table t to zero, if the inner most query returns no data, but Iam finding that, even if I use nvl , it is updating to null. Is this the expected  behaviour or Iam I missing something.


SQL> desc t
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 X                                                NUMBER(10)

SQL> desc t1
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 X                                         NOT NULL NUMBER(38)
 Y                                                  NUMBER(38)

SQL> select count(*) from t1;

  COUNT(*)
----------
         0





SQL>  select * from t;

       X
----------
     1



SQL> update t set X = ( select nvl(y,0) from t2 where y in ( select nvl(y,0)
  2  from t2 ) );

1 row updated.

SQL> commit;

Commit complete.


QL> select * from t
 2  /

      X
--------- 

Tom Kyte
October 30, 2001 - 3:07 pm UTC

You are missing the subtle point that the subquery returns NO rows -- there is "nothing to nvl" as it produces no output.  Hence, what you really really what is the NVL of the subquery!

ops$tkyte@ORA717DEV.US.ORACLE.COM> create table t ( x int );
Table created.

ops$tkyte@ORA717DEV.US.ORACLE.COM> create table t2 ( y int );
Table created.

ops$tkyte@ORA717DEV.US.ORACLE.COM> insert into t values ( 1 );
1 row created.

ops$tkyte@ORA717DEV.US.ORACLE.COM> update t 
                                   <b>set x = nvl( ( select y from t2 ), 0 );</b>
1 row updated.

ops$tkyte@ORA717DEV.US.ORACLE.COM> select * from t;

         X
----------
         0


nvl( subquery, 0 ), not subquery with NVL. 

How about the same, but in PL/SQL

Alla, April 25, 2003 - 10:29 am UTC

Hi Tom;

I have the same problem, when I need to update a table and
set columns to some value, if the subquery does not return
any data.

You suggested:

update t
set x = nvl( ( select y from t2 ), my_value );

and it works fine in SQLPlus, but not in the stored procedure.

I am running this on Oracle 8.1.7. Is it possible in 8.1.7 or do I have to wait till we upgrade to 9.x?

Thanks in advance


Tom Kyte
April 25, 2003 - 3:30 pm UTC

execute immediate
'update t set x = nvl( (select y from t2 ), :my_value )'
using my_value;



A reader, June 30, 2005 - 7:26 pm UTC

Hi Tom,
I am geeting no_data_found in folllowing update statement (it's in stored procedure)

IF s_last_rep.count != 0 THEN
FOR jj IN s_last_rep.FIRST .. s_last_rep.LAST LOOP

dbms_output.put_line( s_last_rep(jj).loss || ' C' ||s_last_rep(jj).cancel||'P '||s_last_rep(jj).pastdue|| '' ||s_last_rep(jj).ed_year );


BEGIN
UPDATE check_edition
SET last_loss = NVL(s_last_rep(jj).loss,last_loss),
last_cancel = NVL(s_last_rep(jj).cancel,last_cancel),
last_pastdue = NVL(s_last_rep(jj).pastdue,last_pastdue)
WHERE edition_year = s_last_rep(jj).ed_year;
EXCEPTION
WHEN others then
dbms_output.put_line('ERROR ' ||SQLERRM);
end;
END LOOP;

END IF;

Could you please help?

Tom Kyte
June 30, 2005 - 9:06 pm UTC

it must have a trigger on it, updates in themselves do not get "no data found", only a select into would. (or the reference of a subscript in a plsql index by table that doesn't exist...)

 
ops$tkyte@ORA9IR2> update t set x = x where 1=0;
 
0 rows updated.
 


so, look for triggers and make sure jj is in range (eg: first..last isn't necessarily correct - it could have 1, 3, 5, and 7 but not 2, 4, 6...) 

A reader, July 01, 2005 - 7:08 am UTC

You are right Tom.

subscript in a plsql index by table didn't exist.

Thanks for the help

Nvl in Subquery

bhaskar, August 28, 2006 - 7:26 am UTC

I did what you mentioned in the clause and use exists clause.
But when i look at the explain plan and find its cost.Earlier it was showing 157 but its showing 1570 by using exists clause .
Please suggest.


Tom Kyte
August 28, 2006 - 10:55 am UTC

which is faster.