Oracle
 sql >> Baza danych >  >> RDS >> Oracle

Jak działa porównanie liczbowe w kolumnie Oracle VARCHAR?

Jak wspomniano w Informacje o języku SQL :

Konwersja niejawna jest wykonywana w kolumnie tabeli, gdy typy nie są zgodne. Można to zobaczyć, śledząc w SQL*Plus, z pewnymi fikcyjnymi danymi.

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

To działa:

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 te błędy:

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)

Zwróć uwagę na różnicę w filtrze; filter("FOO"='10') kontra filter(TO_NUMBER("FOO")=10) . W tym drugim przypadku, porównując z liczbą, to_number() jest wykonywany dla każdego wiersza w tabeli, wynik tej konwersji jest porównywany z wartością stałą. Więc jeśli którejkolwiek z wartości znaków nie można przekonwertować, otrzymasz ORA-01722. Stosowana funkcja spowoduje również zatrzymanie używanego indeksu, jeśli jest on obecny w tej kolumnie.

Interesujące jest to, że masz więcej niż jeden filtr. Oracle może oceniać je w różnej kolejności w różnym czasie, więc nie zawsze możesz zobaczyć ORA-01722 i czasami się pojawi. Załóżmy, że masz where foo = 10 and bar = 'X' . Gdyby Oracle myślało, że może odfiltrować znaki inne niż X najpierw wartości, zastosuje tylko to_number() do tego, co zostało, a ta mniejsza próbka może nie mieć wartości nieliczbowych w foo . Ale jeśli masz and bar = 'Y' , nie-Y wartości mogą zawierać wartości nieliczbowe, lub Oracle może filtrować na foo pierwszy , w zależności od tego, jak selektywne są te wartości.

Morał polega na tym, aby nigdy nie przechowywać informacji liczbowych jako typu znaków.

Szukałem odniesienia do AskTom, aby potwierdzić moralność, a pierwszy, na który spojrzałem wygodnie odnosi się do efektu "zmiany w kolejności predykatu", a także do powiedzenia "nie przechowuj numerów w 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:Jak liczyć wiersze o wartości NULL i NULL?

  2. Lista zadań

  3. zbiorcze wstawianie z Javy do Oracle

  4. Oświadczenie FORALL z klauzulą ​​INDICS-OF Bound w bazie danych Oracle

  5. Przekazywanie parametrów do pliku Oracle SQL z pliku wsadowego