Conforme observado na SQL Language Reference :
A conversão implícita é executada na coluna da tabela quando os tipos não correspondem. Isso pode ser visto rastreando no SQL*Plus, com alguns dados fictícios.
create table t42 (foo varchar2(3 byte));
insert into t42 (foo) values ('10');
insert into t42 (foo) values ('2A');
set autotrace on explain
Isso funciona:
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)
Mas este erros:
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)
Observe a diferença no filtro;
filter("FOO"='10')
versus filter(TO_NUMBER("FOO")=10)
. No último caso, comparando com um número, um to_number()
está sendo executado em todas as linhas da tabela e o resultado dessa conversão é comparado com o valor fixo. Portanto, se algum dos valores de caractere não puder ser convertido, você obterá um ORA-01722. A função que está sendo aplicada também interromperá o uso de um índice, se houver um presente nessa coluna. Onde fica interessante é se você tiver mais de um filtro. A Oracle pode avaliá-los em ordens diferentes em momentos diferentes, então você nem sempre verá o ORA-01722, e ele aparecerá algumas vezes. Digamos que você tenha
where foo = 10 and bar = 'X'
. Se a Oracle pensasse que poderia filtrar o não-X
valores primeiro, só aplicaria o to_number()
para o que resta, e essa amostra menor pode não ter valores não numéricos em foo
. Mas se você tiver and bar = 'Y'
, o não-Y
os valores podem incluir não numéricos, ou Oracle pode filtrar em foo
primeiro , dependendo de quão seletivos são os valores. A moral é nunca armazenar informações numéricas como um tipo de caractere.
Eu estava procurando uma referência do AskTom para fazer backup da moral e do primeiro que olhei convenientemente se refere ao efeito de "uma mudança na ordem de um predicado", além de dizer "não armazene números em varchar2's".