Beberapa poin. Pertama, Anda menyalahgunakan pragma transaksi otonom. Ini dimaksudkan untuk transaksi terpisah yang perlu Anda komit atau kembalikan secara terpisah dari transaksi utama. Anda menggunakannya untuk mengembalikan transaksi utama -- dan Anda tidak pernah melakukan jika tidak ada kesalahan.
Dan "konsekuensi tak terduga" yang disebutkan seseorang? Salah satunya adalah hitungan Anda selalu mengembalikan 0. Jadi hapus pragma keduanya karena disalahgunakan dan hitungan akan mengembalikan nilai yang tepat.
Hal lain adalah tidak memiliki komit atau rollback di dalam pemicu. Naikkan kesalahan dan biarkan kode pengontrol melakukan apa yang perlu dilakukan. Saya tahu kemunduran itu karena pragma. Jangan lupa untuk menghapusnya saat Anda menghapus pragma.
Pemicu berikut berfungsi untuk saya:
CREATE OR REPLACE TRIGGER trg_mytable_biu
BEFORE INSERT OR UPDATE ON mytable
FOR EACH ROW
WHEN (NEW.TYPEB = 'Bert') -- Don't even execute unless this is Bert
DECLARE
L_COUNT NUMBER;
BEGIN
SELECT COUNT(*) INTO L_COUNT
FROM MYTABLE
WHERE ARTICLE = :NEW.ARTICLE
AND TYPEB = :NEW.TYPEB;
IF L_COUNT > 0 THEN
RAISE_APPLICATION_ERROR( -20001, 'Bert already exists!' );
ELSIF :NEW.STOCK_COUNT > 1 THEN
RAISE_APPLICATION_ERROR( -20001, 'Can''t insert more than one Bert!' );
END IF;
END;
Namun, bukanlah ide yang baik untuk pemicu pada tabel untuk mengakses tabel itu secara terpisah. Biasanya sistem bahkan tidak mengizinkannya -- pemicu ini tidak akan dijalankan sama sekali jika diubah menjadi "setelah". Jika diizinkan untuk dieksekusi, seseorang tidak akan pernah bisa memastikan hasil yang diperoleh - seperti yang sudah Anda ketahui. Sebenarnya, saya sedikit terkejut pemicu di atas berfungsi. Saya akan merasa tidak nyaman menggunakannya dalam database nyata.
Opsi terbaik saat pemicu harus mengakses tabel target adalah menyembunyikan tabel di belakang tampilan dan menulis pemicu "bukan" pada tampilan. Itu trigger dapat mengakses tabel semaunya.