For Oracle support & training call (800) 766-1884
Free Oracle Tips

Home
Oracle Tips
Oracle Code Depot
Oracle Monitoring
Oracle Consulting
Oracle Training
Oracle News
Oracle Forum
Oracle Support





 

Free Oracle Tips

image

 
HTML Text

Free Oracle App Server Tips

image

 
HTML Text


Privacy Policy

Redneck

Dress Code

Oracle tuning

Oracle training

Oracle support

Remote Oracle


 

   
  Oracle Tips by Burleson

The SELECT INTO Clause

As the last example showed, even if an invalid state value is passed to the function, the internal query will raise an exception and the function will handle it and return an appropriate value indicating no authors were found. 

There are a number of SQL attributes that are also available for use with the SELECT INTOquery; however the attributes are not as useful when used in PL/SQL code.  Below is a list of the attributes.

            SQL%NOTFOUND - True if no rows returned.

            SQL%FOUND  - True if one or more rows returned

            SQL%ISOPEN - True if the SQL cursor is open.

            SQL%ROWCOUNT - Number of rows returned.

Why are these attributes less useful in PL/SQL?  Because of PL/SQL’s ability to raise and handle exceptions, you already know an attribute’s value before you test the attribute.  The code fragment below creates a function that uses the sql%found attribute.

SQL> create or replace function auth_Name
  2    ( v_auth_state IN author.author_state%type)
  3    return varchar2
  4  as
  5    v_authName author.author_last_name%type;
  6  begin
  7    select
  8      author_last_name into v_authName
  9    from
 10      author
 11    where
 12      author_state = v_auth_state;
 13    if SQL%FOUND then return v_authName;
 14    end if;
 15  end;
 16  / 

Function created.

The function compiles and runs returning the results below.  The function uses the sql%found attribute to test that the query returned a values before the function returns.  The example below uses the function.

SQL> select auth_Name('CA') from dual;
 

AUTH_NAME('CA')
--------------------------------------
jeckle
 

What is the issue with using the sql%found attribute on line 13?  Remember, the SELECT INTOthrows an exception if no data is returned.  Therefore, the attribute check at line 13 is unnecessary because if sql%found was false, the query would have already raise an exception and would not executed line 13.    Here is an annotated example of the previous function that implements exception handling.

SQL> create or replace function auth_Name
  2    ( v_auth_state IN author.author_state%type)
  3    return varchar2
  4  as
  5    v_authName author.author_last_name%type;
  6  begin
  7    select
  8      author_last_name into v_authName
  9    from
 10      author
 11    where
 12      author_state = v_auth_state;
 13    if SQL%FOUND then return v_authName;
 14    end if;
 15    exception
 16    when TOO_MANY_ROWS
 17      then
 18          return 'Authors Found: '||SQL%ROWCOUNT;
 19    when NO_DATA_FOUND
 20      then
 21   if SQL%NOTFOUND then return 'No Authors in
                                   that State';
 22        end if;
 23    when others
 24      then raise_application_error(
 25        -20011,'Unknown Exception in authName
                   Function');
 26  end;
 27  /

Function created.

We already know line 13 is redundant, but so is line 21.  The only way line 21 is executed is if the SELECT INTOquery returned no rows and thus sql%notfound would equal true.  But you already know that sql%notfound is true because the statement is contained in the NO_DATA_FOUND exceptionhandler.  We do not need the condition test in lines 13 or 21 because we already know the results.  Notice that the exception handle catches the TOO_MANY_ROWSexception and returns the number of rows found in line 18.  This appears to be logical, but the example below shows that the handle does not return the number of rows.   

SQL> select auth_Name('MO') from dual;
 

AUTH_NAME('MO')
---------------------------------------
Authors Found: 1
 

Since we know from a previous example that there are three authors from Missouri, why did sql%rowcount return only one?  When the query returned the second row, the TOO_MANY_ROWs exception was raised. 

As a result of the raising the exception, sql%rowcount will operate as you would expect.  The attribute sql%rowcount will return zero (0) if the query returned no rows, (but the NO_DATA_FOUND exception is raised) and a one (1), if one or more rows were returned.  As the example shows, using the sql%rowcount attribute with a SELECT INTOquery does not provide any new information about the query’s execution.

The attribute sql%isopen is used to check that the implicit cursor used by the database has been closed.  Since the database opens and closes the cursor used by the query, any test of the attribute will result in a false. 

So to recap, if sql%found is true, the query did note raise an exception, so why check it.  If the attribute sql%notfound is true, the NO_DATA_FOUND exceptionhas already been raised so the only place to check the attribute value is in the exception handler, which your code would not be executing if data was found. 

The sql%isopen attribute will always be false, because the database opens and closes the implicit cursor used to retrieve the data.  And finally, the attribute sql%rowcount equals 0 if no rows were found (but the exception is raised) and a 1, if one or more rows are found (if more than one an exception is raised).   

The one place you can use some of these attributes is inside an exception handler, as shown in the example below.

SQL> create or replace function auth_Name
  2    ( v_auth_state IN author.author_state%type)
  3    return varchar2
  4  as
  5    v_authName author.author_last_name%type;
  6  begin
  7    select
  8      author_last_name into v_authName
  9    from
 10      author
 11    where
 12      author_state = v_auth_state;
 13    return v_authName;
 14    exception
 15    when others
 16      then
 17        if SQL%NOTFOUND then return 'No Authors
              in that State';
 18        elsif SQL%FOUND then return 'Too Many
              Authors in that State';
 19        else raise_application_error(
 20       -20011,'Unknown Exception in authName
                  Function');
 21        end if;
 22  end;
 23  / 

Function created.
 

SQL> select auth_Name('CA') from dual; 

AUTH_NAME('CA')
---------------------------
jeckle

SQL> select auth_Name('MO') from dual; 

AUTH_NAME('MO')
---------------------------
Too Many Authors in that State

SQL> select auth_Name('FL') from dual; 

AUTH_NAME('FL')
---------------------------
No Authors in that State

In the example above, all the exceptions are caught by the OTHERS clause and handled internally using the IF/THEN/ELSE statement.  The code produces the same results as the original example. 

So, which coding method is better?  The best choice is the one that is clearest to the programmers that have to create and maintain the code.  Many times an exception handler will handle some exceptions and use the OTHERS clauseto raise exceptions based on the SQL attributes and the SQLERR codes.

But what do we do if we know that our query will return zero or more rows and we want to process each of the rows returned?  In this case you must use a cursor to retrieve and process however many rows the query returns.


The above book excerpt is from:

Easy Oracle PL/SQL Programming

Get Started Fast with Working PL/SQL Code Examples

ISBN 0-9759135-7-3   

John Garmany 

http://www.rampant-books.com/book_2005_1_easy_plsql.htm


For more details and scripts, see my new book " Oracle Tuning: The Definitive Reference", over 900 pages of BC's favorite tuning tips & scripts. 

You can buy it direct from the publisher for 30%-off and get instant access to the code depot.

  
 

 
 
 
 
Oracle performance tuning software
 
 

 

 
 
 
Oracle performance Tuning 10g reference poster
 
 
 
Oracle training in Linux commands
 
Oracle training Excel
 
Oracle training & performance tuning books
 

 

Fast-Track Oracle Support
PO Box 511
Kittrell, NC 27544


Email BC: