Oracle
 sql >> Database >  >> RDS >> Oracle

Come funziona il confronto numerico sulla colonna Oracle VARCHAR?

Come indicato nel Riferimento al linguaggio SQL :

La conversione implicita viene eseguita sulla colonna della tabella quando i tipi non corrispondono. Questo può essere visto tracciando in SQL*Plus, con alcuni dati fittizi.

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

Funziona:

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)

Ma questo errori:

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)

Nota la differenza nel filtro; filter("FOO"='10') rispetto a filter(TO_NUMBER("FOO")=10) . In quest'ultimo caso, confrontando con un numero, un to_number() viene eseguito su ogni riga della tabella il risultato di tale conversione viene confrontato con il valore fisso. Quindi, se uno qualsiasi dei valori dei caratteri non può essere convertito, otterrai un ORA-01722. La funzione applicata interromperà anche l'utilizzo di un indice, se presente su quella colonna.

Dove diventa interessante è se hai più di un filtro. Oracle potrebbe valutarli in ordini diversi in momenti diversi, quindi potresti non vedere sempre ORA-01722 e a volte apparirà. Supponi di avere where foo = 10 and bar = 'X' . Se Oracle pensasse di poter filtrare la non X prima i valori, applicherebbe solo il to_number() a ciò che resta e quel campione più piccolo potrebbe non avere valori non numerici in foo . Ma se hai and bar = 'Y' , il non Y i valori potrebbero includere non numerici, o Oracle potrebbe filtrare su foo prima , a seconda di quanto ritiene selettivi i valori.

La morale è di non memorizzare mai informazioni numeriche come tipo di carattere.

Stavo cercando un riferimento AskTom per sostenere la morale e il il primo che ho guardato si riferisce convenientemente all'effetto di "un cambiamento nell'ordine di un predicato" oltre a dire "non memorizzare numeri in varchar2".