Access
 sql >> Teknologi Basis Data >  >> RDS >> Access

Merancang Pemicu Microsoft T-SQL

Mendesain Pemicu Microsoft T-SQL

Saat membangun proyek yang melibatkan front-end Access dan backend SQL Server, kami menghadapi pertanyaan ini. Haruskah kita menggunakan pemicu untuk sesuatu? Merancang pemicu SQL Server untuk aplikasi Access mungkin merupakan solusi tetapi hanya setelah pertimbangan yang cermat. Terkadang ini disarankan sebagai cara untuk menjaga logika bisnis dalam database, daripada aplikasi. Biasanya, saya suka logika bisnis didefinisikan sedekat mungkin dengan database. Jadi, apakah trigger adalah solusi yang kami inginkan untuk front-end Access kami?

Saya telah menemukan bahwa pengkodean pemicu SQL memerlukan pertimbangan tambahan dan jika kita tidak berhati-hati, kita bisa berakhir dengan kekacauan yang lebih besar daripada yang kita mulai. Artikel ini bertujuan untuk membahas semua jebakan dan teknik yang dapat kita gunakan untuk memastikan bahwa ketika kita membangun database dengan pemicu, pemicu akan bekerja untuk keuntungan kita, bukan hanya menambah kerumitan demi kerumitan.

Mari kita pertimbangkan aturannya…

Aturan #1:Jangan gunakan pemicu!

Dengan serius. Jika Anda meraih pemicunya di pagi hari, maka Anda akan menyesalinya di malam hari. Masalah terbesar dengan pemicu secara umum adalah mereka dapat secara efektif mengaburkan logika bisnis Anda dan mengganggu proses yang seharusnya tidak memerlukan pemicu. Saya telah melihat beberapa saran untuk mematikan pemicu ketika Anda melakukan beban massal atau yang serupa. Saya menegaskan bahwa ini adalah bau kode besar. Anda tidak boleh menggunakan pemicu jika harus diaktifkan atau dinonaktifkan secara kondisional.

Sebagai default, kita harus menulis prosedur atau tampilan tersimpan terlebih dahulu. Untuk sebagian besar skenario, mereka akan melakukan pekerjaan dengan baik. Jangan tambahkan keajaiban di sini.

Jadi mengapa artikel tentang pemicu itu?

Karena pemicu memang memiliki kegunaannya. Kita perlu mengenali kapan kita harus menggunakan pemicu. Kita juga perlu menuliskannya dengan cara yang membantu kita lebih dari menyakiti kita.

Aturan #2:Apakah saya benar-benar membutuhkan pemicu?

Secara teori, pemicu terdengar bagus. Mereka memberi kami model berbasis peristiwa untuk mengelola perubahan segera setelah diubah. Tetapi jika yang Anda butuhkan hanyalah memvalidasi beberapa data, atau memastikan bahwa beberapa kolom atau tabel logging tersembunyi telah terisi…. Saya pikir Anda akan menemukan bahwa prosedur tersimpan melakukan pekerjaan lebih efisien dan menghilangkan aspek ajaib. Selanjutnya, menulis prosedur tersimpan mudah untuk diuji; cukup atur beberapa data tiruan dan jalankan prosedur tersimpan, verifikasi hasilnya sesuai dengan yang Anda harapkan. Saya harap Anda menggunakan kerangka kerja pengujian seperti tSQLt.

Dan penting untuk dicatat bahwa biasanya lebih efisien menggunakan batasan basis data daripada pemicu. Jadi, jika Anda hanya perlu memvalidasi bahwa suatu nilai valid di tabel lain, gunakan batasan kunci asing. Memvalidasi bahwa suatu nilai berada dalam rentang tertentu memerlukan batasan pemeriksaan. Itu harus menjadi pilihan default Anda untuk validasi semacam itu.

Jadi, kapan kita benar-benar membutuhkan pemicu?

Itu bermuara pada kasus di mana Anda benar-benar ingin logika bisnis berada di lapisan SQL. Mungkin karena Anda memiliki banyak klien dalam bahasa pemrograman berbeda yang melakukan penyisipan/pembaruan ke tabel. Akan sangat berantakan untuk menduplikasi logika bisnis di setiap klien dalam bahasa pemrograman masing-masing dan ini juga berarti lebih banyak bug. Untuk skenario di mana tidak praktis untuk membuat lapisan tingkat menengah, pemicu adalah tindakan terbaik Anda untuk menegakkan aturan bisnis yang tidak dapat dinyatakan sebagai batasan.

Untuk menggunakan contoh khusus untuk Access. Misalkan kita ingin menerapkan logika bisnis saat memodifikasi data melalui aplikasi. Mungkin kita memiliki beberapa formulir entri data yang terikat pada satu tabel yang sama, atau mungkin kita perlu mendukung formulir entri data yang kompleks di mana beberapa tabel dasar harus berpartisipasi dalam pengeditan. Mungkin formulir entri data perlu mendukung entri yang tidak dinormalisasi yang kemudian kami susun ulang menjadi data yang dinormalisasi. Dalam semua kasus itu, kami hanya bisa menulis kode VBA tetapi itu bisa sulit untuk dipertahankan dan divalidasi untuk semua kasus. Pemicu membantu kita memindahkan logika dari VBA ke T-SQL. Logika bisnis yang berpusat pada data umumnya paling baik ditempatkan sedekat mungkin dengan data.

Aturan #3:Pemicu harus berbasis set, bukan berbasis baris

Sejauh ini kesalahan paling umum yang dilakukan dengan pemicu adalah membuatnya berjalan dalam baris. Seringkali kita melihat kode yang mirip dengan ini:

--Kode buruk! Jangan gunakan! CREATE TRIGGER dbo.SomeTriggerON dbo.SomeTable SETELAH INSERTASBEGIN MENYATAKAN @NewTotal uang; MENYATAKAN @NewID int; PILIH TOP 1 @NewID =SalesOrderID, @NewTotal =SalesAmount FROM dimasukkan; UPDATE dbo.SalesOrder SET OrderTotal =OrderTotal + @NewTotal WHERE SalesOrderID =@SalesOrderIDEND;

Hadiahnya seharusnya hanya fakta bahwa ada SELECT TOP 1 dari meja dimasukkan. Ini hanya akan berfungsi selama kita memasukkan hanya satu baris. Tapi ketika lebih dari satu baris, lalu apa yang terjadi pada baris sial yang datang ke-2 dan sesudahnya? Kami dapat memperbaikinya dengan melakukan sesuatu yang mirip dengan ini:

--Kode masih buruk! Jangan gunakan! CREATE TRIGGER dbo.SomeTriggerON dbo.SomeTable SETELAH INSERTASMULAI MERGE INTO dbo.SalesOrder AS MENGGUNAKAN dimasukkan AS i ON s.SalesOrderID =i.SalesOrderID KETIKA MATCHED LALU UPDATE SET OrderTotal =OrderTotal;> 

Ini sekarang berbasis set dan dengan demikian jauh lebih baik tetapi ini masih memiliki masalah lain yang akan kita lihat dalam beberapa aturan berikutnya…

Aturan #4:Gunakan tampilan sebagai gantinya.

Tampilan dapat memiliki pemicu yang menyertainya. Ini memberi kita keuntungan untuk menghindari masalah yang terkait dengan pemicu tabel. Kami akan dapat dengan mudah mengimpor data bersih secara massal ke dalam tabel tanpa harus menonaktifkan pemicu apa pun. Selain itu, pemicu pada tampilan menjadikannya pilihan keikutsertaan yang eksplisit. Jika Anda memiliki fungsi terkait keamanan atau aturan bisnis yang mengharuskan menjalankan pemicu, Anda cukup mencabut izin di tabel secara langsung dan dengan demikian menyalurkannya ke tampilan baru. Itu memastikan bahwa Anda akan melalui proyek dan mencatat di mana pembaruan pada tabel diperlukan sehingga Anda kemudian dapat melacaknya untuk kemungkinan bug atau masalah.

Kelemahannya adalah tampilan hanya dapat memiliki INSTEAD OF trigger yang terpasang, yang berarti Anda harus secara eksplisit melakukan sendiri modifikasi yang setara pada tabel dasar di dalam trigger. Namun, saya cenderung berpikir lebih baik seperti itu karena ini juga memastikan bahwa Anda tahu persis apa modifikasi yang akan dilakukan, dan dengan demikian memberi Anda tingkat kontrol yang sama dengan yang biasanya Anda miliki dalam prosedur tersimpan.

Aturan #5:Pemicunya harus sederhana.

Ingat komentar tentang debugging dan pengujian prosedur tersimpan? Bantuan terbaik yang dapat kita lakukan untuk diri kita sendiri adalah menjaga logika bisnis dalam prosedur tersimpan dan meminta pemicu untuk memanggilnya. Anda tidak boleh menulis logika bisnis langsung ke pemicu; yang secara efektif menuangkan beton ke database. Sekarang dibekukan ke bentuknya dan dapat menjadi masalah untuk menguji logika secara memadai. Harness pengujian Anda sekarang harus melibatkan beberapa modifikasi pada tabel dasar. Ini tidak baik untuk menulis tes sederhana dan berulang. Ini harus menjadi yang paling rumit karena pemicu Anda harus diizinkan:

BUAT PEMICU [dbo].[SomeTrigger]ON [dbo].[SomeView] BUKAN INSERT, UPDATE, DELETEASBEGIN DECLARE @SomeIDs SEBAGAI SomeIDTableType --Lakukan penggabungan ke dalam tabel dasar MERGE INTO dbo.SomeTable SEBAGAI t MENGGUNAKAN yang dimasukkan AS i ON t.SomeID =i.SomeID KETIKA COCOK MAKA UPDATE SET t.SomeStuff =i.SomeStuff, t.OtherStuff =i.OtherStuff KETIKA TIDAK COCOK MAKA MASUKKAN ( SomeStuff, OtherStuff ) NILAI ( i.SometherStuff, i.OtherStuff ). OUTPUT dimasukkan.SomeID INTO @SomeIDs(SomeID); DELETE FROM dbo.SomeTable OUTPUT dihapus.SomeID INTO @SomeIDs(SomeID) WHERE EXISTS ( SELECT NULL FROM dihapus AS d WHERE d.SomeID =SomeTable.SomeID ) AND NOT EXISTS ( SELECT NULL FROM dimasukkan AS i WHERE i.SomeID =SomeTable. Beberapa ID ); EXEC dbo.uspUpdateSomeStuff @SomeIDs;END;

Bagian pertama pemicu pada dasarnya adalah melakukan modifikasi aktual pada tabel dasar karena ini adalah pemicu BUKAN, jadi kita harus melakukan semua modifikasi yang akan berbeda tergantung pada tabel yang perlu kita kelola. Perlu ditekankan bahwa modifikasi harus dilakukan secara verbatim. Kami tidak menghitung ulang atau mengubah data apa pun. Kami menyimpan semua pekerjaan ekstra itu di akhir, di mana semua yang kami lakukan di dalam pemicu adalah mengisi daftar catatan yang dimodifikasi oleh pemicu dan menyediakan prosedur tersimpan menggunakan parameter bernilai tabel. Perhatikan bahwa kami bahkan tidak mempertimbangkan catatan apa yang diubah atau bagaimana itu diubah. Semua itu dapat dilakukan dalam prosedur tersimpan.

Aturan #6:Pemicu harus idempoten bila memungkinkan.

Secara umum, pemicu HARUS menjadi idempoten. Ini berlaku terlepas dari apakah itu pemicu berbasis tabel atau berbasis tampilan. Ini berlaku terutama untuk mereka yang perlu memodifikasi data pada tabel dasar dari mana pemicu memantau. Mengapa? Karena jika manusia memodifikasi data yang akan diambil oleh pemicu, mereka mungkin menyadari bahwa mereka melakukan kesalahan, mengeditnya lagi atau mungkin hanya mengedit catatan yang sama dan menyimpannya 3 kali. Mereka tidak akan senang jika menemukan bahwa laporan berubah setiap kali mereka melakukan pengeditan yang tidak seharusnya mengubah hasil laporan.

Untuk lebih jelasnya, mungkin tergoda untuk mencoba dan mengoptimalkan pemicu dengan melakukan sesuatu yang mirip dengan ini:

DENGAN SourceData SEBAGAI ( SELECT OrderID, SUM(SalesAmount) AS NewSaleTotal FROM dimasukkan GROUP BY OrderID)BERGABUNG KE dbo.SalesOrder AS menggunakan SourceData AS dON o.OrderID =d.OrderIDWHEN MATCHED THE N UPDATE SET o.OrderTotal =o.OrderTotal =+ d.NewSaleTotal;

Kita dapat menghindari penghitungan ulang total baru dengan hanya meninjau baris yang dimodifikasi dalam tabel yang disisipkan, bukan? Tetapi ketika pengguna mengedit catatan untuk memperbaiki kesalahan ketik pada nama pelanggan, apa yang akan terjadi? Kami berakhir dengan total palsu, dan pemicunya sekarang bekerja melawan kami.

Sekarang, Anda akan melihat mengapa aturan #4 membantu kami dengan mendorong hanya kunci utama ke prosedur tersimpan, daripada mencoba meneruskan data apa pun ke dalam prosedur tersimpan atau melakukannya langsung di dalam pemicu seperti yang akan dilakukan sampel .

Sebagai gantinya, kami ingin memiliki beberapa kode yang mirip dengan ini dalam prosedur tersimpan:

BUAT PROSEDUR dbo.uspUpdateSalesTotal ( @SalesOrders SalesOrderTableType READONLY) ASMULAI DENGAN SourceData AS ( SELECT s.OrderID, SUM(s.SalesAmount) AS NewSaleTotal FROM dbo.SalesOrder SEBAGAI MANA ADA ( SELECT NULLder FROM) .SalesOrderID =s.SalesOrderID ) GROUP BY OrderID ) GABUNG KE dbo.SalesOrder SEBAGAI MENGGUNAKAN SourceData SEBAGAI d PADA o.OrderID =d.OrderID KETIKA COCOK LALU UPDATE SET o.OrderTotal =d.NewSaleTotal;END;
 Menggunakan @SalesOrders, kami masih dapat secara selektif memperbarui hanya baris yang terpengaruh oleh pemicu, dan kami juga dapat menghitung ulang total baru dan menjadikannya total baru. Jadi meskipun pengguna salah ketik pada nama pelanggan dan mengeditnya, setiap penyimpanan akan menghasilkan hasil yang sama untuk baris tersebut.

Lebih penting lagi, pendekatan ini juga memberi kita cara mudah untuk memperbaiki totalnya. Misalkan kita harus melakukan impor massal, dan impor itu tidak memuat total sehingga kita harus menghitungnya sendiri. Kita dapat menulis prosedur tersimpan untuk menulis ke tabel secara langsung. Kami kemudian dapat menjalankan prosedur tersimpan di atas yang meneruskan ID dari impor, dan kami semua baik-baik saja. Dengan demikian, logika yang kita gunakan tidak terikat pada pemicu di belakang tampilan. Itu membantu ketika logika tidak diperlukan untuk impor massal yang kami lakukan.

Jika Anda mengalami masalah dalam membuat pemicu idempoten, ini merupakan indikasi kuat bahwa Anda mungkin perlu menggunakan prosedur tersimpan dan memanggilnya langsung dari aplikasi Anda alih-alih mengandalkan pemicu. Satu pengecualian penting untuk aturan ini adalah ketika pemicu utamanya dimaksudkan sebagai pemicu audit. Dalam hal ini, Anda ingin menulis baris baru ke tabel audit untuk setiap pengeditan, termasuk semua kesalahan ketik yang dibuat pengguna. Ini tidak masalah karena dalam kasus tersebut, tidak ada perubahan pada data yang berinteraksi dengan pengguna. Dari POV pengguna, hasilnya masih sama. Namun, kapan pun pemicu perlu memanipulasi data yang sama dengan yang digunakan pengguna, akan jauh lebih baik jika pemicunya idempoten.

Menutup

Mudah-mudahan sekarang, Anda dapat melihat betapa lebih sulitnya merancang pemicu yang berperilaku baik. Untuk alasan itu, Anda harus mempertimbangkan dengan hati-hati apakah Anda dapat menghindarinya sama sekali dan menggunakan pemanggilan langsung dengan prosedur tersimpan. Tetapi jika Anda telah menyimpulkan bahwa Anda harus memiliki pemicu untuk mengelola modifikasi yang dilakukan melalui tampilan, saya harap aturan akan membantu Anda. Membuat set pemicu cukup mudah dengan beberapa penyesuaian. Membuatnya idempoten biasanya membutuhkan lebih banyak pemikiran tentang bagaimana Anda akan menerapkan prosedur tersimpan Anda.

Jika Anda memiliki saran atau aturan lain untuk dibagikan, tulis di komentar!


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Microsoft Azure:Apa itu dan Bagaimana Manfaat Bisnis Anda

  2. Gotchas Saat Menggunakan Microsoft Access Runtime

  3. Pentingnya Desain Database yang Baik (dan 7 Langkah untuk Mencapainya)

  4. Produk Microsoft Office yang Menolak Mati

  5. Periksa Sumber Kontrol dari Semua Kontrol di Proyek MS Access Anda