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

Bagaimana Access berbicara dengan sumber data ODBC? Bagian 4

Apa yang Access lakukan saat pengguna membuat perubahan pada data di tabel tertaut ODBC?

Seri penelusuran ODBC kami berlanjut, dan dalam artikel keempat ini kami akan menjelaskan cara memasukkan dan memperbarui catatan data dalam kumpulan catatan, serta proses penghapusan catatan. Di artikel sebelumnya, kita mempelajari bagaimana Access menangani pengisian data dari sumber ODBC. Kami melihat bahwa tipe recordset memiliki efek penting pada bagaimana Access akan memformulasi kueri ke sumber data ODBC. Lebih penting lagi, kami menemukan bahwa dengan recordset tipe dynaset, Access melakukan pekerjaan tambahan untuk memiliki semua informasi yang diperlukan untuk dapat memilih satu baris menggunakan kunci. Ini akan berlaku dalam artikel ini di mana kita mengeksplorasi bagaimana modifikasi data ditangani. Kita akan mulai dengan penyisipan, yang merupakan operasi paling rumit, kemudian beralih ke pembaruan dan akhirnya penghapusan.

Memasukkan record ke dalam recordset

Perilaku penyisipan recordset tipe dynaset akan bergantung pada bagaimana Access memahami kunci dari tabel yang mendasarinya. Akan ada 3 perilaku yang berbeda. Dua yang pertama berurusan dengan penanganan kunci utama yang dibuat secara otomatis oleh server dalam beberapa cara. Yang kedua adalah kasus khusus dari perilaku pertama yang hanya berlaku dengan backend SQL Server menggunakan IDENTITY kolom. Yang terakhir berkaitan dengan kasus ketika kunci disediakan oleh pengguna (misalnya kunci alami sebagai bagian dari entri data). Kita akan mulai dengan kasus yang lebih umum dari kunci yang dibuat oleh server.

Memasukkan catatan; tabel dengan kunci utama yang dibuat oleh server

Saat kita memasukkan recordset (sekali lagi, bagaimana kita melakukannya, melalui Access UI atau VBA tidak masalah), Access harus melakukan sesuatu untuk menambahkan baris baru ke cache lokal.

Yang penting untuk diperhatikan adalah bahwa Access memiliki perilaku penyisipan yang berbeda tergantung pada bagaimana kunci diatur. Dalam hal ini, Cities tabel tidak memiliki IDENTITY atribut melainkan menggunakan SEQUENCE objek untuk menghasilkan kunci baru. Inilah SQL terlacak yang diformat:

SQLExecDirect:
INSERT INTO  "Application"."Cities"  (
   "CityName"
  ,"StateProvinceID"
  ,"LatestRecordedPopulation"
  ,"LastEditedBy"
) VALUES (
   ?
  ,?
  ,?
  ,?)

SQLPrepare:
SELECT
   "CityID"
  ,"CityName"
  ,"StateProvinceID"
  ,"Location"
  ,"LatestRecordedPopulation"
  ,"LastEditedBy"
  ,"ValidFrom"
  ,"ValidTo"
FROM "Application"."Cities"
WHERE "CityID" IS NULL

SQLExecute: (GOTO BOOKMARK)

SQLExecDirect:
SELECT
  "Application"."Cities"."CityID"
FROM "Application"."Cities"
WHERE "CityName" = ?
  AND "StateProvinceID" = ?
  AND "LatestRecordedPopulation" = ?
  AND "LastEditedBy" = ?

SQLExecute: (GOTO BOOKMARK)

SQLExecute: (MULTI-ROW FETCH)
Perhatikan bahwa Access hanya akan mengirimkan kolom yang benar-benar diubah oleh pengguna. Meskipun kueri itu sendiri menyertakan lebih banyak kolom, kami hanya mengedit 4 kolom, jadi Access hanya akan menyertakannya. Itu memastikan bahwa Access tidak mengganggu kumpulan perilaku default untuk kolom lain yang tidak diubah pengguna, karena Access tidak memiliki pengetahuan khusus tentang bagaimana sumber data akan menangani kolom tersebut. Di luar itu, pernyataan sisipan cukup sesuai dengan yang kami harapkan.

Namun, pernyataan kedua agak aneh. Ini memilih untuk WHERE "CityID" IS NULL . Tampaknya tidak mungkin, karena kita sudah tahu bahwa CityID kolom adalah kunci utama dan menurut definisi tidak boleh nol. Namun, jika Anda melihat tangkapan layar, kami tidak pernah mengubah CityID kolom. Dari POV Access, ini adalah NULL . Kemungkinan besar, Access mengadopsi pendekatan pesimistis dan tidak akan berasumsi bahwa sumber data sebenarnya akan mematuhi standar SQL. Seperti yang kita lihat dari bagian yang membahas bagaimana Access memilih indeks yang akan digunakan untuk mengidentifikasi baris secara unik, itu mungkin bukan kunci utama tetapi hanya UNIQUE indeks yang memungkinkan NULL . Untuk kasus tepi yang tidak mungkin, itu melakukan kueri hanya untuk memastikan bahwa sumber data tidak benar-benar membuat catatan baru dengan nilai itu. Setelah memeriksa bahwa tidak ada data yang dikembalikan, ia kemudian mencoba mencari catatan lagi dengan filter berikut:

WHERE "CityName" = ?
  AND "StateProvinceID" = ?
  AND "LatestRecordedPopulation" = ?
  AND "LastEditedBy" = ?
yang merupakan 4 kolom yang sama yang benar-benar dimodifikasi pengguna. Karena hanya ada satu kota bernama "Zeke", kami hanya mendapatkan satu catatan kembali, dan dengan demikian Access kemudian dapat mengisi cache lokal dengan catatan baru dengan data yang sama seperti yang dimiliki sumber data. Ini akan memasukkan perubahan apa pun ke kolom lain, karena SELECT daftar hanya menyertakan CityID key, yang kemudian akan digunakan dalam pernyataan yang sudah disiapkan untuk kemudian mengisi seluruh baris menggunakan CityID kunci.

Memasukkan catatan; tabel dengan kunci utama peningkatan otomatis

Namun, bagaimana jika tabel berasal dari database SQL Server dan memiliki kolom peningkatan otomatis seperti IDENTITY atribut? Access berperilaku berbeda. Jadi mari kita buat salinan Cities tabel tetapi edit sehingga CityID kolom sekarang menjadi IDENTITY kolom.

Mari kita lihat bagaimana Access menangani ini:

SQLExecDirect:
INSERT INTO "Application"."Cities" (
   "CityName"
  ,"StateProvinceID"
  ,"LatestRecordedPopulation"
  ,"LastEditedBy"
  ,"ValidFrom"
  ,"ValidTo"
) VALUES (
   ?
  ,?
  ,?
  ,?
  ,?
  ,?)

SQLExecDirect:
SELECT @@IDENTITY

SQLExecute: (GOTO BOOKMARK)

SQLExecute: (GOTO BOOKMARK)
Ada lebih sedikit obrolan; kita cukup melakukan SELECT @@IDENTITY untuk menemukan identitas yang baru dimasukkan. Sayangnya, ini bukan perilaku umum. Misalnya, MySQL mendukung kemampuan untuk melakukan SELECT @@IDENTITY , namun, Access tidak akan menyediakan perilaku ini. Driver ODBC PostgreSQL memiliki mode untuk meniru SQL Server untuk mengelabui Access agar mengirimkan @@IDENTITY ke PostgreSQL sehingga dapat dipetakan ke serial yang setara tipe data.

Memasukkan catatan dengan nilai eksplisit untuk kunci utama

Mari kita lakukan percobaan ke-3 menggunakan tabel dengan int normal kolom, tanpa IDENTITY atribut. Meskipun ini akan tetap menjadi kunci utama di tabel, kami ingin melihat bagaimana perilakunya saat kami secara eksplisit memasukkan kunci itu sendiri.

SQLExecDirect:
INSERT INTO  "Application"."Cities" (
   "CityID"
  ,"CityName"
  ,"StateProvinceID"
  ,"LatestRecordedPopulation"
  ,"LastEditedBy"
  ,"ValidFrom"
  ,"ValidTo"
) VALUES (
   ?
  ,?
  ,?
  ,?
  ,?
  ,?
  ,?
)

SQLExecute: (GOTO BOOKMARK)

SQLExecute: (MULTI-ROW FETCH)
Kali ini, tidak ada senam tambahan; karena kami telah memberikan nilai untuk kunci utama, Access mengetahui bahwa ia tidak perlu mencoba dan menemukan baris itu lagi; itu hanya mengeksekusi pernyataan yang disiapkan untuk menyinkronkan ulang baris yang dimasukkan. Kembali ke desain awal di mana Cities tabel menggunakan SEQUENCE objek untuk menghasilkan kunci baru, kita dapat menambahkan fungsi VBA untuk mengambil nomor baru menggunakan NEXT VALUE FOR dan dengan demikian mengisi kunci secara proaktif untuk mendapatkan kita perilaku ini. Ini lebih mendekati cara kerja mesin database Access; segera setelah kami mengotori catatan, itu mengambil kunci baru dari AutoNumber tipe data, daripada menunggu sampai record benar-benar dimasukkan. Jadi, jika database Anda menggunakan SEQUENCE atau cara lain untuk membuat kunci, mungkin ada gunanya menyediakan mekanisme pengambilan kunci secara proaktif untuk membantu menghilangkan dugaan yang kami lihat dilakukan Access dengan contoh pertama.

Memperbarui record dalam recordset

Tidak seperti sisipan di bagian sebelumnya, pembaruan relatif lebih mudah karena kami sudah memiliki kunci yang ada. Dengan demikian, Access biasanya berperilaku lebih lugas dalam hal pembaruan. Ada dua perilaku utama yang perlu kita pertimbangkan saat memperbarui catatan yang bergantung pada keberadaan kolom versi baris.

Memperbarui catatan tanpa kolom versi baris

Misalkan kita memodifikasi hanya satu kolom. Inilah yang kita lihat di ODBC.

SQLExecute: (GOTO BOOKMARK)

SQLExecDirect:
UPDATE "Application"."Cities"
SET "CityName"=?
WHERE "CityID" = ?
  AND "CityName" = ?
  AND "StateProvinceID" = ?
  AND "Location" IS NULL
  AND "LatestRecordedPopulation" = ?
  AND "LastEditedBy" = ?
  AND "ValidFrom" = ?
  AND "ValidTo" = ?
Hmm, apa masalahnya dengan semua kolom tambahan yang tidak kami modifikasi? Nah, sekali lagi, Access harus mengambil sikap pesimistis. Itu harus mengasumsikan bahwa seseorang mungkin telah mengubah data saat pengguna perlahan-lahan meraba-raba pengeditan. Tapi bagaimana Access tahu bahwa orang lain mengubah data di server? Nah, secara logis, jika semua kolom sama persis, maka seharusnya hanya memperbarui satu baris, bukan? Itulah yang dicari Access saat membandingkan semua kolom; untuk memastikan bahwa pembaruan hanya akan memengaruhi tepat satu baris. Jika ditemukan bahwa itu memperbarui lebih dari satu baris atau nol baris, itu mengembalikan pembaruan dan mengembalikan kesalahan atau #Deleted kepada pengguna.

Tapi ... itu agak tidak efisien, bukan? Lebih jauh lagi, ini bisa membawa masalah jika ada logika sisi server yang mungkin mengubah nilai input oleh pengguna. Sebagai ilustrasi, misalkan kita menambahkan pemicu konyol yang mengubah nama kota (tentu saja kami tidak menyarankan ini):

CREATE TRIGGER SillyTrigger
ON Application.Cities AFTER UPDATE AS
BEGIN
  UPDATE Application.Cities
  SET CityName = 'zzzzz'
  WHERE EXISTS (
    SELECT NULL
    FROM inserted AS i
    WHERE Cities.CityID = i.CityID
  );
END;
Jadi jika kita kemudian mencoba memperbarui baris dengan mengubah nama kota, tampaknya berhasil.

Tetapi jika kami kemudian mencoba mengeditnya lagi, kami mendapatkan pesan kesalahan dengan pesan yang disegarkan:

Ini adalah output dari sqlout.txt :

SQLExecDirect:
UPDATE "Application"."Cities"
SET "CityName"=?
WHERE "CityID" = ?
  AND "CityName" = ?
  AND "StateProvinceID" = ?
  AND "Location" IS NULL
  AND "LatestRecordedPopulation" = ?
  AND "LastEditedBy" = ?
  AND "ValidFrom" = ?
  AND "ValidTo" = ?

SQLExecute: (GOTO BOOKMARK)

SQLExecute: (GOTO BOOKMARK)

SQLExecute: (MULTI-ROW FETCH)

SQLExecute: (MULTI-ROW FETCH)
Penting untuk dicatat bahwa GOTO BOOKMARK ke-2 dan MULTI-ROW FETCH subsequent berikutnya es tidak terjadi sampai kami mendapatkan pesan kesalahan dan mengabaikannya. Alasannya adalah saat kami mengotori catatan, Access melakukan GOTO BOOKMARK , sadari bahwa data yang dikembalikan tidak lagi sesuai dengan yang ada di cache, yang menyebabkan kita mendapatkan pesan “Data telah diubah”. Itu mencegah kita membuang waktu mengedit catatan yang pasti gagal karena sudah basi. Perhatikan bahwa Access juga pada akhirnya akan menemukan perubahan jika kami memberinya cukup waktu untuk menyegarkan data. Dalam hal ini, tidak akan ada pesan kesalahan; lembar data hanya akan diperbarui untuk menampilkan data yang benar.

Namun, dalam kasus tersebut, Access memiliki kunci yang tepat sehingga tidak ada masalah dalam menemukan data baru. Tetapi jika itu adalah kunci yang rapuh? Jika pemicu telah mengubah kunci utama atau sumber data ODBC tidak mewakili nilai persis seperti yang diperkirakan Access, itu akan menyebabkan Access melukis catatan sebagai #Deleted karena tidak dapat mengetahui apakah itu diedit oleh server atau orang lain versus apakah itu dihapus secara sah oleh orang lain.

Memperbarui catatan dengan kolom versi baris

Either way, mendapatkan pesan kesalahan atau #Deleted bisa sangat mengganggu. Tetapi ada cara untuk menghindari Access membandingkan semua kolom. Mari kita hapus pemicunya dan tambahkan kolom baru:

ALTER TABLE Application.Cities
ADD RV rowversion NOT NULL;
Kami menambahkan rowversion yang memiliki properti terkena ODBC sebagai memiliki SQLSpecialColumns(SQL_ROWVER) , yang perlu diketahui Access agar dapat digunakan sebagai cara untuk membuat versi baris. Mari kita lihat bagaimana pembaruan bekerja dengan perubahan ini.

SQLExecDirect: UPDATE "Application"."Cities" 
SET "CityName"=?  
WHERE "CityID" = ? 
  AND "RV" = ?

SQLExecute: (GOTO BOOKMARK)
Berbeda dengan contoh sebelumnya di mana Access membandingkan nilai di setiap kolom, apakah pengguna mengeditnya atau tidak, kami hanya memperbarui catatan menggunakan RV sebagai kriteria filter. Alasannya adalah jika RV masih memiliki nilai yang sama dengan yang diberikan Access, maka Access dapat yakin bahwa baris ini tidak diedit oleh orang lain karena jika demikian, maka RV nilainya akan berubah.

Ini juga berarti bahwa jika pemicu mengubah data atau jika SQL Server dan Access tidak mewakili satu nilai dengan cara yang persis sama (misalnya angka mengambang), Access tidak akan menolak saat memilih kembali baris yang diperbarui dan kembali dengan yang berbeda nilai di kolom lain yang tidak diedit pengguna.

CATATAN :Tidak semua produk DBMS akan menggunakan istilah yang sama. Sebagai contoh, timestamp MySQL dapat digunakan sebagai versi baris untuk tujuan ODBC. Anda perlu membaca dokumentasi produk untuk melihat apakah produk tersebut mendukung fitur versi baris sehingga Anda dapat memanfaatkan perilaku ini dengan Access.

Tampilan dan versi baris

Tampilan juga dipengaruhi oleh ada atau tidak adanya versi baris. Misalkan kita membuat tampilan di SQL Server dengan definisi:

CREATE VIEW dbo.vwCities AS
SELECT
	CityID,
	CityName
FROM Application.Cities;
Memperbarui catatan pada tampilan akan kembali ke perbandingan kolom demi kolom seolah-olah kolom versi baris tidak ada di tabel:

SQLExecDirect: UPDATE "dbo"."vwCities" SET "CityName"=?  WHERE "CityID" = ? AND "CityName" = ?
Oleh karena itu, jika Anda memerlukan perilaku pembaruan berbasis versi baris, Anda harus berhati-hati untuk memastikan bahwa kolom versi baris disertakan dalam tampilan. Dalam kasus tampilan yang berisi beberapa tabel dalam gabungan, sebaiknya sertakan setidaknya kolom versi baris dari tabel yang ingin Anda perbarui. Karena biasanya hanya satu tabel yang dapat diperbarui, termasuk hanya satu versi baris mungkin sudah cukup sebagai aturan umum.

Menghapus sebuah record dalam sebuah recordset

Penghapusan catatan berperilaku serupa dengan pembaruan dan juga akan menggunakan versi baris jika tersedia. Pada tabel tanpa versi baris, kita mendapatkan:

SQLExecDirect: 
DELETE FROM "Application"."Cities" 
WHERE "CityID" = ? 
  AND "CityName" = ? 
  AND "StateProvinceID" = ? 
  AND "Location" IS NULL 
  AND "LatestRecordedPopulation" = ? 
  AND "LastEditedBy" = ? 
  AND "ValidFrom" = ? 
  AND "ValidTo" = ?
Pada tabel dengan versi baris, kita mendapatkan:

SQLExecDirect: 
DELETE FROM "Application"."Cities" 
WHERE "CityID" = ? 
  AND "RV" = ?
Sekali lagi, Access harus pesimis tentang penghapusan seperti halnya memperbarui; itu tidak ingin menghapus baris yang diubah oleh orang lain. Oleh karena itu, ia menggunakan perilaku yang sama seperti yang kita lihat saat memperbarui untuk mencegah beberapa pengguna mengubah catatan yang sama.

Kesimpulan

Kami telah mempelajari bagaimana Access menangani modifikasi data dan menjaga cache lokalnya tetap sinkron dengan sumber data ODBC. Kami melihat betapa pesimisnya Access, yang didorong oleh kebutuhan untuk mendukung sebanyak mungkin sumber data ODBC tanpa bergantung pada asumsi atau ekspektasi tertentu bahwa sumber data ODBC tersebut akan mendukung fitur tertentu. Untuk alasan itu, kami melihat bahwa Access akan berperilaku berbeda tergantung pada bagaimana kunci didefinisikan untuk tabel tertaut ODBC yang diberikan. Jika kami dapat menyisipkan kunci baru secara eksplisit, ini membutuhkan kerja minimal dari Access untuk menyinkronkan ulang cache lokal untuk rekaman yang baru dimasukkan. Namun, jika kami mengizinkan server untuk mengisi kunci, Access harus melakukan pekerjaan tambahan di latar belakang untuk menyinkronkan ulang.

Kami juga melihat bahwa memiliki kolom pada tabel yang dapat digunakan sebagai versi baris dapat membantu mengurangi obrolan antara Access dan sumber data ODBC pada pembaruan. Anda perlu berkonsultasi dengan dokumentasi driver ODBC untuk menentukan apakah itu mendukung versi baris pada lapisan ODBC dan jika demikian, sertakan kolom tersebut dalam tabel atau tampilan sebelum menautkan ke Access untuk mendapatkan manfaat dari pembaruan berbasis versi baris.

Sekarang kita tahu bahwa untuk pembaruan atau penghapusan apa pun, Access akan selalu mencoba memverifikasi bahwa baris tidak diubah sejak terakhir diambil oleh Access, untuk mencegah pengguna membuat perubahan yang mungkin tidak terduga. Namun, kita perlu mempertimbangkan efek yang timbul dari membuat perubahan di tempat lain (misalnya pemicu sisi server, menjalankan kueri berbeda di koneksi lain) yang dapat menyebabkan Access menyimpulkan bahwa baris telah diubah dan dengan demikian melarang perubahan. Informasi tersebut akan membantu kami menganalisis dan menghindari pembuatan urutan modifikasi data yang mungkin bertentangan dengan harapan Access saat mensinkronisasi ulang cache lokal.

Pada artikel berikutnya, kita akan melihat efek penerapan filter pada recordset.

Dapatkan bantuan dari Pakar Akses kami hari ini. Hubungi tim kami di 773-809-5456 atau kirimkan email kepada kami di [email protected].


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Pentingnya Memelihara Database yang Sesuai dengan HIPAA

  2. Akses Pandangan Pakar tentang KTT MVP 2020

  3. Seret dan Jatuhkan Di MS Access dan Penyortiran Bersyarat

  4. Cara Mengubah Ukuran Kontrol Formulir di Access 2016

  5. Database SQL Server Importir Wide World yang kompatibel dengan akses