Jak je uvedeno v Reference jazyka SQL :
Pokud se typy neshodují, provede se ve sloupci tabulky implicitní převod. To lze vidět trasováním v SQL*Plus s některými fiktivními daty.
create table t42 (foo varchar2(3 byte));
insert into t42 (foo) values ('10');
insert into t42 (foo) values ('2A');
set autotrace on explain
Toto funguje:
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)
Ale tyto chyby:
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)
Všimněte si rozdílu ve filtru; filter("FOO"='10')
versus filter(TO_NUMBER("FOO")=10)
. V druhém případě, v porovnání s číslem, to_number()
se provádí proti každému řádku v tabulce, výsledek tohoto převodu se porovnává s pevnou hodnotou. Pokud tedy některou z hodnot znaků nelze převést, získáte ORA-01722. Aplikovaná funkce také zastaví používání indexu, pokud je v tomto sloupci přítomen.
Zajímavé je, že máte více než jeden filtr. Oracle je může vyhodnocovat v různých pořadích v různých časech, takže ORA-01722 nemusíte vždy vidět a někdy se objeví. Řekněme, že jste měli where foo = 10 and bar = 'X'
. Kdyby si Oracle myslel, že by mohl odfiltrovat non-X
hodnoty, použije pouze to_number()
k tomu, co zbývá, a tento menší vzorek nemusí mít nečíselné hodnoty v foo
. Ale pokud máte and bar = 'Y'
, jiné než Y
hodnoty mohou zahrnovat jiné než číselné hodnoty, nebo Oracle může filtrovat podle foo
první , v závislosti na tom, jak selektivní považuje hodnoty za.
Morálkou je nikdy neukládat číselné informace jako typ znaku.
Hledal jsem odkaz AskTom na podporu morálky a první, na kterou jsem se podíval příhodně odkazuje na efekt „změny v pořadí predikátu“ a také na „neukládejte čísla do varchar2“.