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

Apakah pernyataan CASE dan DECODE setara?

Jawaban singkat, tidak.

Jawaban yang sedikit lebih panjang hampir.

Hanya muncul bahwa hasil yang diperoleh dari setiap pernyataan adalah identik. Jika kita menggunakan fungsi DUMP untuk mengevaluasi tipe data yang dikembalikan, Anda akan mengerti maksud saya:

SQL> select dump(case 1 when 2 then null else 0 end) as simple_case
  2       , dump(case when 1 = 2 then null else 0 end) as searched_case
  3       , dump(decode(1, 2, null, 0)) as decode
  4    from dual;

SIMPLE_CASE        SEARCHED_CASE      DECODE
------------------ ------------------ -----------------
Typ=2 Len=1: 128   Typ=2 Len=1: 128   Typ=1 Len=1: 48

SQL Fiddle

Anda dapat melihat bahwa tipe data DECODE adalah 1, sedangkan dua pernyataan KASUS "mengembalikan" tipe data 2. Menggunakan Ringkasan Tipe Data Oracle, DECODE mengembalikan VARCHAR2 (tipe data 1) sedangkan pernyataan KASUS adalah "mengembalikan " angka (tipe data 2).

Saya berasumsi ini terjadi karena, seperti namanya, DECODE adalah fungsi dan CASE tidak, yang menyiratkan bahwa mereka telah diimplementasikan secara berbeda secara internal. Tidak ada cara nyata untuk membuktikan ini.

Anda mungkin berpikir bahwa ini tidak benar-benar memengaruhi apa pun. Jika Anda membutuhkannya sebagai angka, Oracle akan secara implisit mengonversi karakter menjadi angka di bawah aturan konversi implisit, bukan? Ini juga tidak benar, ini tidak akan berfungsi di UNION karena tipe data memiliki menjadi identik; Oracle tidak akan melakukan konversi implisit untuk mempermudah Anda. Kedua, inilah yang dikatakan Oracle tentang konversi implisit:

Oracle menyarankan agar Anda menentukan konversi eksplisit, daripada mengandalkan konversi implisit atau otomatis, karena alasan berikut:

  • Pernyataan SQL lebih mudah dipahami saat Anda menggunakan fungsi konversi tipe data eksplisit.

  • Konversi tipe data implisit dapat berdampak negatif pada performa, terutama jika tipe data dari nilai kolom diubah menjadi konstanta, bukan sebaliknya.

  • Konversi implisit tergantung pada konteks di mana itu terjadi dan mungkin tidak bekerja dengan cara yang sama dalam setiap kasus. Misalnya, konversi implisit dari nilai datetime ke nilai VARCHAR2 dapat menghasilkan tahun yang tidak terduga bergantung pada nilai parameter NLS_DATE_FORMAT.

  • Algoritma untuk konversi implisit dapat berubah di seluruh rilis perangkat lunak dan di antara produk Oracle. Perilaku konversi eksplisit lebih dapat diprediksi.

Itu bukan daftar yang bagus; tetapi poin kedua dari belakang membawa saya dengan baik ke kencan. Jika kita mengambil kueri sebelumnya dan mengonversinya menjadi kueri yang menggunakan tanggal sebagai gantinya:

select case sysdate when trunc(sysdate) then null 
                    else sysdate 
       end as simple_case
     , case when sysdate = trunc(sysdate) then null 
            else sysdate 
       end as searched_case
     , decode(sysdate, trunc(sysdate), null, sysdate) as decode
  from dual;

Sekali lagi, menggunakan DUMP pada kueri ini, pernyataan CASE mengembalikan tipe data 12, sebuah DATE. DECODE telah mengonversi sysdate menjadi VARCHAR2.

SQL> select dump(case sysdate when trunc(sysdate) then null
  2                           else sysdate
  3              end) as simple_case
  4       , dump(case when sysdate = trunc(sysdate) then null
  5                   else sysdate
  6              end) as searched_case
  7       , dump(decode(sysdate, trunc(sysdate), null, sysdate)) as decode
  8    from dual;

SIMPLE_CASE          
---------------------------------- 
Typ=12 Len=7: 120,112,12,4,22,18,7 
SEARCHED_CASE
---------------------------------- 
Typ=12 Len=7: 120,112,12,4,22,18,7
DECODE
---------------------------------- 
Typ=1 Len=19: 50,48,49,50,45,49,50,45,48,52,32,50,49,58,49,55,58,48,54

SQL Fiddle

Perhatikan (dalam SQL Fiddle) bahwa DATE telah diubah menjadi karakter menggunakan sesi NLS_DATE_FORMAT.

Memiliki tanggal yang secara implisit diubah menjadi VARCHAR2 dapat menyebabkan masalah. Jika Anda bermaksud menggunakan TO_CHAR, untuk mengonversi tanggal menjadi karakter, kueri Anda akan pecah di tempat yang tidak Anda harapkan.

SQL> select to_char( decode( sysdate
  2                         , trunc(sysdate), null
  3                         , sysdate )
  4                 , 'yyyy-mm-dd') as to_char
  5    from dual;
select to_char( decode( sysdate
                *
ERROR at line 1:
ORA-01722: invalid number

SQL Fiddle

Demikian pula, aritmatika tanggal tidak lagi berfungsi:

SQL>
SQL>
SQL> select decode(sysdate, trunc(sysdate), null, sysdate) + 1 as decode
  2    from dual;
select decode(sysdate, trunc(sysdate), null, sysdate) + 1 as decode
       *
ERROR at line 1:
ORA-01722: invalid number

SQL Fiddle

Menariknya DECODE hanya mengubah ekspresi menjadi VARCHAR2 jika salah satu hasil yang mungkin adalah NULL. Jika nilai default adalah NULL maka ini tidak terjadi. Misalnya:

SQL> select decode(sysdate, sysdate, sysdate, null) as decode
  2    from dual;

DECODE
-------------------
2012-12-04 21:18:32

SQL> select dump(decode(sysdate, sysdate, sysdate, null)) as decode
  2    from dual;

DECODE
------------------------------------------    
Typ=13 Len=8: 220,7,12,4,21,18,32,0

SQL Fiddle

Perhatikan bahwa DECODE telah mengembalikan tipe data 13. Ini tidak didokumentasikan tetapi, menurut saya, merupakan tipe tanggal karena aritmatika tanggal, dll. berfungsi.

Singkatnya, hindari DECODE jika Anda bisa; Anda mungkin belum tentu mendapatkan tipe data yang Anda harapkan. Mengutip Tom Kyte:

Decode agak tidak jelas -- CASE sangat sangat jelas. Hal-hal yang mudah dilakukan dalam decode mudah dilakukan di CASE, hal-hal yang sulit atau hampir tidak mungkin dilakukan dengan decode mudah dilakukan di CASE. CASE, secara logika, menang telak.

Untuk melengkapinya ada dua fungsional perbedaan antara DECODE dan CASE.

  1. DECODE tidak dapat digunakan dalam PL/SQL.
  2. CASE tidak dapat digunakan untuk membandingkan null secara langsung

    SQL> select case null when null then null else 1 end as case1
      2        , case when null is null then null else 1 end as case2
      3        , decode(null, null, null, 1) as decode
      4    from dual
      5         ;
    
         CASE1      CASE2 DECODE
    ---------- ---------- ------
             1
    

    SQL Fiddle



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Bagaimana saya bisa melihat kueri yang dieksekusi terhadap Oracle?

  2. Bagaimana memulihkan database menggunakan RMAN

  3. Mengapa Oracle menggunakan DBMS_STATS.GATHER_TABLE_STATS?

  4. Menginstal Oracle 12c Enterprise Edition di Windows 7

  5. Redaksi Data 12c