Som anges i SQL Language Reference :
Implicit konvertering utförs i tabellkolumnen när typerna inte matchar. Detta kan ses genom att spåra i SQL*Plus, med lite dummydata.
create table t42 (foo varchar2(3 byte));
insert into t42 (foo) values ('10');
insert into t42 (foo) values ('2A');
set autotrace on explain
Detta fungerar:
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 detta fel:
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)
Notera skillnaden i filtret; filter("FOO"='10')
kontra filter(TO_NUMBER("FOO")=10)
. I det senare fallet, jämför man med ett tal, en to_number()
utförs mot varje rad i tabellen jämförs resultatet av den konverteringen mot det fasta värdet. Så om något av teckenvärdena inte kan konverteras, får du en ORA-01722. Funktionen som tillämpas kommer också att stoppa ett index som används, om ett sådant finns i den kolumnen.
Där det blir intressant är om du har mer än ett filter. Oracle kan utvärdera dem i olika ordningsföljder vid olika tidpunkter, så du kanske inte alltid ser ORA-01722, och den dyker upp ibland. Säg att du hade where foo = 10 and bar = 'X'
. Om Oracle trodde att det kunde filtrera bort icke-X
värden först, skulle det bara tillämpa to_number()
till det som är kvar, och det mindre urvalet kanske inte har icke-numeriska värden i foo
. Men om du har and bar = 'Y'
, icke-Y
värden kan innehålla icke-numeriska värden, eller Oracle kan filtrera på foo
först , beroende på hur selektiva den tror att värdena är.
Moralen är att aldrig lagra numerisk information som en teckentyp.
Jag letade efter en AskTom-referens för att backa upp moralen, och första jag tittade på hänvisar bekvämt till effekten av "en förändring i ordningen för ett predikat" samt att säga "lagra inte nummer i varchar2's".