Oracle
 sql >> Teknologi Basis Data >  >> RDS >> Oracle

Bagaimana cara kerja perbandingan numerik pada kolom Oracle VARCHAR?

Seperti yang tercantum dalam Referensi Bahasa SQL :

Konversi implisit dilakukan pada kolom tabel ketika jenisnya tidak cocok. Ini dapat dilihat dengan menelusuri di SQL*Plus, dengan beberapa data dummy.

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

Ini berfungsi:

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)

Tapi kesalahan ini:

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)

Perhatikan perbedaan filternya; filter("FOO"='10') versus filter(TO_NUMBER("FOO")=10) . Dalam kasus terakhir, membandingkan dengan angka, to_number() sedang dilakukan terhadap setiap baris dalam tabel, hasil konversi itu dibandingkan dengan nilai tetap. Jadi jika salah satu nilai karakter tidak dapat dikonversi, Anda akan mendapatkan ORA-01722. Fungsi yang diterapkan juga akan menghentikan penggunaan indeks, jika ada indeks di kolom tersebut.

Yang menarik adalah jika Anda memiliki lebih dari satu filter. Oracle dapat mengevaluasinya dalam urutan yang berbeda pada waktu yang berbeda, jadi Anda mungkin tidak selalu melihat ORA-01722, dan terkadang akan muncul. Katakanlah Anda memiliki where foo = 10 and bar = 'X' . Jika Oracle berpikir itu bisa menyaring non-X nilai terlebih dahulu, itu hanya akan menerapkan to_number() ke apa yang tersisa, dan sampel yang lebih kecil itu mungkin tidak memiliki nilai non-numerik di foo . Tetapi jika Anda memiliki and bar = 'Y' , non-Y nilai mungkin termasuk non-numerik, atau Oracle mungkin memfilter pada foo pertama , tergantung pada seberapa selektif nilai tersebut.

Pesan moralnya adalah jangan pernah menyimpan informasi numerik sebagai tipe karakter.

Saya mencari referensi AskTom untuk mendukung moral, dan yang pertama saya lihat dengan mudah mengacu pada efek "perubahan dalam urutan predikat" serta mengatakan "jangan simpan angka di 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. Cara mengulang kolom dengan PL/SQL

  2. Mengganti System.Data.OracleClient ke Oracle.DataAccess (ODP.NET)

  3. Oracle Select * mengembalikan baris tetapi Select count(1) mengembalikan 0

  4. Memahami Java Oracle di Mac

  5. Kondisi (seperti suka) pada bidang biner (gumpalan) di oracle