Oracle
 sql >> база данни >  >> RDS >> Oracle

Как работи числовото сравнение на колона VARCHAR на Oracle?

Както е отбелязано в Справочник за SQL език :

Неявното преобразуване се извършва в колоната на таблицата, когато типовете не съвпадат. Това може да се види чрез проследяване в SQL*Plus, с някои фиктивни данни.

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

Това работи:

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)

Но тези грешки:

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)

Обърнете внимание на разликата във филтъра; filter("FOO"='10') спрямо filter(TO_NUMBER("FOO")=10) . В последния случай, сравняване с число, to_number() се извършва срещу всеки ред в таблицата, резултатът от това преобразуване се сравнява с фиксираната стойност. Така че, ако някоя от стойностите на знаците не може да бъде преобразувана, ще получите ORA-01722. Приложената функция също ще спре използването на индекс, ако има такъв в тази колона.

Там, където става интересно, е, ако имате повече от един филтър. Oracle може да ги оцени в различни редове по различно време, така че може да не виждате винаги ORA-01722 и понякога ще изскача. Да кажем, че сте имали where foo = 10 and bar = 'X' . Ако Oracle реши, че може да филтрира неX първо стойности, ще приложи само to_number() до това, което е останало, и тази по-малка проба може да няма нечислови стойности в foo . Но ако имате and bar = 'Y' , не-Y стойностите може да включват нечислови стойности, или Oracle може да филтрира по foo първо , в зависимост от това колко селективни според него са стойностите.

Моралът е никога да не съхранявате числова информация като символен тип.

Търсех препратка към AskTom, за да подкрепя морала, и първият, който погледнах удобно се отнася до ефекта на "промяна в реда на предикат", както и казвайки "не съхранявайте числа във varchar2".



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. разрешение за създаване на синоними на друга схема (Oracle)

  2. Последици за производителността от използването на (DBMS_RLS) Oracle Row Level Security (RLS)?

  3. Ограждането на имена на колони в двойни кавички с команда CREATE в Oracle не работи правилно. Защо?

  4. как да направите избирането на произволни редове в oracle по-бързо с таблица с милиони редове

  5. Използване на keep-alive:ORA-00933:SQL командата не е приключила правилно