Som nævnt i SQL sprogreference :
Implicit konvertering udføres i tabelkolonnen, når typerne ikke matcher. Dette kan ses ved at spore i SQL*Plus, med nogle dummy-data.
create table t42 (foo varchar2(3 byte));
insert into t42 (foo) values ('10');
insert into t42 (foo) values ('2A');
set autotrace on explain
Dette virker:
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)
Men dette fejler:
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)
Bemærk forskellen i filteret; filter("FOO"='10')
versus filter(TO_NUMBER("FOO")=10)
. I sidstnævnte tilfælde sammenligner man med et tal, en to_number()
udføres mod hver række i tabellen, sammenlignes resultatet af denne konvertering med den faste værdi. Så hvis nogen af tegnværdierne ikke kan konverteres, får du en ORA-01722. Funktionen, der anvendes, vil også stoppe et indeks i at blive brugt, hvis et sådant er til stede i den kolonne.
Hvor det bliver interessant er, hvis du har mere end et filter. Oracle kan evaluere dem i forskellige rækkefølger på forskellige tidspunkter, så du kan ikke altid se ORA-01722, og den dukker nogle gange op. Lad os sige, at du havde where foo = 10 and bar = 'X'
. Hvis Oracle troede, at det kunne filtrere ikke-X
fra værdier først, ville det kun anvende to_number()
til det, der er tilbage, og den mindre prøve har muligvis ikke ikke-numeriske værdier i foo
. Men hvis du har and bar = 'Y'
, ikke-Y
værdier kan omfatte ikke-numeriske værdier, eller Oracle filtrerer muligvis på foo
først , alt efter hvor selektive den mener værdierne er.
Moralen er aldrig at gemme numerisk information som en karaktertype.
Jeg ledte efter en AskTom-reference til at sikkerhedskopiere moralen og første jeg så på henviser bekvemt til effekten af "en ændring i rækkefølgen af et prædikat" såvel som at sige "gem ikke numre i varchar2's".