Oracle
 sql >> Datenbank >  >> RDS >> Oracle

Wie funktioniert der numerische Vergleich in der Oracle VARCHAR-Spalte?

Wie in der SQL-Sprachreferenz angegeben :

Die implizite Konvertierung wird für die Tabellenspalte durchgeführt, wenn die Typen nicht übereinstimmen. Dies kann durch Ablaufverfolgung in SQL*Plus mit einigen Dummy-Daten gesehen werden.

create table t42 (foo varchar2(3 byte));
insert into t42 (foo) values ('10');
insert into t42 (foo) values ('2A');
set autotrace on explain

Das funktioniert:

select * from t42 where foo = '10';

FOO
---
10

Execution Plan
----------------------------------------------------------
Plan hash value: 3843907281

--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |     1 |     3 |     3   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| T42  |     1 |     3 |     3   (0)| 00:00:01 |
--------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("FOO"='10')

Note
-----
   - dynamic sampling used for this statement (level=2)

Aber dieser Fehler:

select * from t42 where foo = 10;

ERROR:
ORA-01722: invalid number



Execution Plan
----------------------------------------------------------
Plan hash value: 3843907281

--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |     1 |     3 |     3   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| T42  |     1 |     3 |     3   (0)| 00:00:01 |
--------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter(TO_NUMBER("FOO")=10)

Beachten Sie den Unterschied im Filter; filter("FOO"='10') gegenüber filter(TO_NUMBER("FOO")=10) . Im letzteren Fall, Vergleich mit einer Zahl, einem to_number() für jede Zeile in der Tabelle durchgeführt wird, wird das Ergebnis dieser Konvertierung mit dem festen Wert verglichen. Wenn also einer der Zeichenwerte nicht konvertiert werden kann, erhalten Sie einen ORA-01722. Die angewendete Funktion stoppt auch die Verwendung eines Index, falls einer für diese Spalte vorhanden ist.

Interessant wird es, wenn Sie mehr als einen Filter haben. Oracle kann sie zu unterschiedlichen Zeiten in unterschiedlichen Reihenfolgen auswerten, sodass ORA-01722 möglicherweise nicht immer angezeigt wird und manchmal auftaucht. Angenommen, Sie hatten where foo = 10 and bar = 'X' . Wenn Oracle dachte, es könnte das Nicht-X herausfiltern Werte zuerst, würde es nur to_number() anwenden zu dem, was übrig ist, und diese kleinere Stichprobe enthält möglicherweise keine nicht numerischen Werte in foo . Aber wenn Sie and bar = 'Y' haben , das Nicht-Y Werte können nicht-numerische Zeichen, oder enthalten Oracle filtert möglicherweise nach foo zuerst , je nachdem, wie selektiv die Werte sind.

Die Moral ist, numerische Informationen niemals als Zeichentyp zu speichern.

Ich habe nach einer AskTom-Referenz gesucht, um die Moral zu untermauern, und nach dem das erste, das ich mir angesehen habe bezieht sich praktischerweise auf den Effekt von "einer Änderung in der Reihenfolge eines Prädikats" sowie auf die Aussage "Speichere keine Zahlen in varchar2's".