Skip to Main Content
  • Questions
  • Quick test for the presence of a non numeric value

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question, Marius.

Asked: October 29, 2009 - 11:44 am UTC

Last updated: October 29, 2009 - 12:41 pm UTC

Version: 9.2.0.7.0

Viewed 1000+ times

You Asked

Hi Tom

I thought it was possible to make à quick test for the presence of non numeric values with this query, but obvisioulsy I was wrong. What do you think about this situation, is it normal?

Connected to Oracle9i Enterprise Edition Release 9.2.0.7.0 
Connected as mni
 
SQL> 
SQL> create table t_mni (
  2    id         number(10),
  3    faux_nr    varchar2(10)
  4  )
  5  /
 
Table created
SQL> insert into t_mni(id, faux_nr) Values (1, '10')
  2  /
 
1 row inserted
SQL> insert into t_mni(id, faux_nr) Values (2, 'A')
  2  /
 
1 row inserted
SQL> commit
  2  /
 
Commit complete
SQL> select to_number(faux_nr)
  2    from t_mni
  3  /
 
select to_number(faux_nr)
  from t_mni
 
ORA-01722: Nombre non valide
SQL> select count(*)
  2    from (
  3          select to_number(faux_nr)
  4            from t_mni
  5          )
  6  /
 
  COUNT(*)
----------
         2
 
SQL> 

and Tom said...

select count(*) from (select to_number(faux_nr) from t_mni)

is the same as

select count(*) from (select null from t_mni);

(eg: count the number of rows)

which is of course the same as

select count(*) from t_mni;

Now, the optimizer knows that is really just counting rows - it 'knows' the columns in the select list (the projection) and not necessary.

counting a set is not a good thing to do unless your answer is to be "how many rows are in this set".


I see people try to 'benchmark' a query Q by:

select count(*) from (Q)

not realizing that the plan for Q by itself is almost certainly a lot different than the plan for "select count(*) from (q)" is. We can do things very differently.



ops$tkyte%ORA10GR2> exec dbms_stats.set_table_stats( user, 'T_MNI', numrows => 100000 );

PL/SQL procedure successfully completed.

ops$tkyte%ORA10GR2> set autotrace traceonly explain
ops$tkyte%ORA10GR2> select count(*)
  2    from (select to_number(faux_nr) from t_mni)
  3  /

Execution Plan
----------------------------------------------------------
Plan hash value: 1760092885

--------------------------------------------------------------------
| Id  | Operation          | Name  | Rows  | Cost (%CPU)| Time     |
--------------------------------------------------------------------
|   0 | SELECT STATEMENT   |       |     1 |     9  (12)| 00:00:01 |
|   1 |  SORT AGGREGATE    |       |     1 |            |          |
|   2 |   TABLE ACCESS FULL| T_MNI |   100K|     9  (12)| 00:00:01 |
--------------------------------------------------------------------

ops$tkyte%ORA10GR2> alter table t_mni add constraint t_mni_pk primary key(id);

Table altered.

ops$tkyte%ORA10GR2> select count(*)
  2    from (select to_number(faux_nr) from t_mni)
  3  /

Execution Plan
----------------------------------------------------------
Plan hash value: 2504573254

---------------------------------------------------------------------
| Id  | Operation        | Name     | Rows  | Cost (%CPU)| Time     |
---------------------------------------------------------------------
|   0 | SELECT STATEMENT |          |     1 |     1   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE  |          |     1 |            |          |
|   2 |   INDEX FULL SCAN| T_MNI_PK |   100K|     1   (0)| 00:00:01 |
---------------------------------------------------------------------




notice how after we add a primary key - the full scan of the table disappears and we answer the question using an index that doesn't even contain the column you referenced!!!!



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

More to Explore

PL/SQL demos

Check out more PL/SQL tutorials on our LiveSQL tool.

PL/SQL docs

PL/SQL reference manual from the Oracle documentation library