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

Memahami perbedaan antara Tabel dan API Transaksi

Mari kita mulai dengan Tabel API. Ini adalah praktik memediasi akses ke tabel melalui PL/SQL API. Jadi, kami memiliki paket per tabel, yang harus dihasilkan dari kamus data. Paket tersebut menyajikan seperangkat prosedur standar untuk mengeluarkan DML terhadap tabel dan beberapa fungsi untuk mengambil data.

Sebagai perbandingan, API Transaksional mewakili Unit Kerja. Itu tidak mengekspos informasi apa pun tentang objek database yang mendasarinya sama sekali. API Transaksional menawarkan enkapsulasi yang lebih baik, dan antarmuka yang lebih bersih.

Kontrasnya seperti ini. Pertimbangkan aturan bisnis ini untuk membuat Departemen baru:

  1. Departemen baru harus memiliki Nama dan Lokasi
  2. Departemen baru harus memiliki seorang manajer, yang harus merupakan Karyawan lama
  3. Karyawan lama lainnya dapat dipindahkan ke Departemen baru
  4. Karyawan baru dapat ditugaskan ke Departemen baru
  5. Departemen baru harus memiliki setidaknya dua Karyawan yang ditugaskan (termasuk manajer)

Menggunakan API Tabel, transaksi mungkin terlihat seperti ini:

DECLARE
    dno pls_integer;
    emp_count pls_integer;
BEGIN
    dept_utils.insert_one_rec(:new_name, :new_loc, dno);
    emp_utils.update_one_rec(:new_mgr_no ,p_job=>'MGR’ ,p_deptno=>dno);
    emp_utils.update_multi_recs(:transfer_emp_array, p_deptno=>dno);
    FOR idx IN :new_hires_array.FIRST..:new_hires_array.LAST LOOP
        :new_hires_array(idx).deptno := dno;
    END LOOP;
    emp_utils.insert_multi_recs(:new_hires_array);
    emp_count := emp_utils.get_count(p_deptno=>dno); 
    IF emp_count < 2 THEN
        raise_application_error(-20000, ‘Not enough employees’);
    END IF;
END;
/

Sedangkan dengan API Transaksional jauh lebih sederhana:

DECLARE
    dno subtype_pkg.deptno;
BEGIN
    dept_txns.create_new_dept(:new_name
                                , :new_loc
                                , :new_mgr_no
                                , :transfer_emps_array
                                , :new_hires_array
                                , dno);
END;
/

Jadi mengapa perbedaan dalam mengambil data? Karena pendekatan API Transaksional tidak mendukung get() generic generik berfungsi untuk menghindari penggunaan pernyataan SELECT yang tidak efisien.

Misalnya, jika Anda hanya menginginkan gaji dan komisi untuk seorang Karyawan, tanyakan ini ...

select sal, comm
into l_sal, l_comm
from emp
where empno = p_eno;

... lebih baik daripada menjalankan ini ...

l_emprec := emp_utils.get_whole_row(p_eno);

...terutama jika catatan Karyawan memiliki kolom LOB.

Ini juga lebih efisien daripada:

l_sal := emp_utils.get_sal(p_eno);
l_comm := emp_utils.get_comm(p_eno);

... jika masing-masing getter tersebut mengeksekusi pernyataan SELECT yang terpisah. Yang tidak diketahui:ini adalah praktik OO buruk yang mengarah pada kinerja basis data yang mengerikan.

Pendukung Tabel API memperdebatkannya atas dasar bahwa mereka melindungi pengembang dari kebutuhan untuk memikirkan SQL. Orang-orang yang mencelanya tidak menyukai Tabel API untuk alasan yang sama . Bahkan API Tabel terbaik cenderung mendorong pemrosesan RBAR. Jika kita menulis SQL kita sendiri setiap kali kita cenderung memilih pendekatan berbasis set.

Menggunakan API Transaksional tidak serta merta mengesampingkan penggunaan get_resultset() fungsi. Masih ada banyak nilai dalam API kueri. Tapi itu lebih cenderung dibangun dari tampilan dan fungsi yang mengimplementasikan gabungan daripada SELECT pada tabel individual.

Kebetulan, saya pikir membangun API Transaksional di atas Tabel API bukanlah ide yang baik:kami masih memiliki pernyataan SQL yang terpisah alih-alih gabungan yang ditulis dengan hati-hati.

Sebagai ilustrasi, berikut adalah dua implementasi berbeda dari API transaksional untuk memperbarui gaji setiap Karyawan di suatu Wilayah (Wilayah menjadi bagian skala besar organisasi; Departemen ditugaskan ke Wilayah).

Versi pertama tidak memiliki SQL murni hanya panggilan Tabel API, saya tidak berpikir ini adalah manusia jerami:ini menggunakan jenis fungsionalitas yang saya lihat dalam paket Tabel API (walaupun beberapa menggunakan SQL dinamis daripada prosedur bernama SET_XXX()) .

create or replace procedure adjust_sal_by_region
    (p_region in dept.region%type
           , p_sal_adjustment in number )
as
    emps_rc sys_refcursor;
    emp_rec emp%rowtype;
    depts_rc sys_refcursor;
    dept_rec dept%rowtype;
begin
    depts_rc := dept_utils.get_depts_by_region(p_region);

    << depts >>
    loop
        fetch depts_rc into dept_rec;
        exit when depts_rc%notfound;
        emps_rc := emp_utils.get_emps_by_dept(dept_rec.deptno);

        << emps >>
        loop
            fetch emps_rc into emp_rec;
            exit when emps_rc%notfound;
            emp_rec.sal := emp_rec.sal * p_sal_adjustment;
            emp_utils.set_sal(emp_rec.empno, emp_rec.sal);
        end loop emps;

    end loop depts;

end adjust_sal_by_region;
/

Implementasi yang setara dalam SQL:

create or replace procedure adjust_sal_by_region
    (p_region in dept.region%type
           , p_sal_adjustment in number )
as
begin
    update emp e
    set e.sal = e.sal * p_sal_adjustment
    where e.deptno in ( select d.deptno 
                        from dept d
                        where d.region = p_region );
end adjust_sal_by_region;
/

Ini jauh lebih bagus daripada loop kursor bersarang dan pembaruan baris tunggal dari versi sebelumnya. Ini karena dalam SQL sangat mudah untuk menulis gabungan, kita perlu memilih Karyawan berdasarkan Wilayah. Jauh lebih sulit menggunakan API Tabel, karena Wilayah bukan kunci Karyawan.

Agar adil, jika kita memiliki API Tabel yang mendukung SQL dinamis, semuanya lebih baik tetapi masih belum ideal:

create or replace procedure adjust_sal_by_region
    (p_region in dept.region%type
           , p_sal_adjustment in number )
as
    emps_rc sys_refcursor;
    emp_rec emp%rowtype;
begin
    emps_rc := emp_utils.get_all_emps(
                    p_where_clause=>'deptno in ( select d.deptno 
                        from dept d where d.region = '||p_region||' )' );

    << emps >>
    loop
        fetch emps_rc into emp_rec;
        exit when emps_rc%notfound;
        emp_rec.sal := emp_rec.sal * p_sal_adjustment;
        emp_utils.set_sal(emp_rec.empno, emp_rec.sal);
    end loop emps;

end adjust_sal_by_region;
/

kata terakhir

Setelah mengatakan semua itu, ada skenario di mana Tabel API dapat berguna, situasi ketika kita hanya ingin berinteraksi dengan tabel tunggal dengan cara yang cukup standar. Kasus yang jelas mungkin menghasilkan atau menggunakan umpan data dari sistem lain, mis. ETL.

Jika Anda ingin menyelidiki penggunaan API Tabel, tempat terbaik untuk memulai adalah Utilitas Quest CodeGen Steven Feuerstein (sebelumnya QNXO). Ini sama baiknya dengan generator TAPI, dan gratis.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Cari Tahu Kuartal Mana yang Termasuk Tanggal di Oracle

  2. Memetakan kunci asing dengan nama kolom khusus

  3. Oracle SQL mengembalikan baris dengan cara yang sewenang-wenang ketika tidak ada klausa urutan dengan yang digunakan

  4. Metadata mengenai tipe record level paket PL/SQL

  5. Bagaimana cara mendapatkan parameter output prosedur tersimpan yang merupakan array agar berfungsi?