Mendapatkan Kesalahan 3340 Permintaan '' rusak saat menjalankan permintaan DoCmd.RunSQL

83

Sejak menginstal pembaruan windows untuk Office 2010 menyelesaikan KB 4484127 saya mendapatkan kesalahan saat menjalankan query yang berisi klausa WHERE.

Misalnya menjalankan kueri ini:

DoCmd.RunSQL "update users set uname= 'bob' where usercode=1"

Hasil dalam kesalahan ini:

Nomor kesalahan = 3340 Permintaan '' rusak

The pembaruan tersebut saat ini masih terpasang:

Cuplikan layar memperlihatkan pembaruan Microsoft Office 2010 Paket Layanan 2 448127

Bagaimana saya bisa menjalankan kueri dengan sukses? Haruskah saya hapus instalasi pembaruan ini?

Zvi Redler
sumber

Jawaban:

92

Ringkasan

Ini adalah bug yang diketahui disebabkan oleh pembaruan Office yang dirilis pada 12 November 2019. Bug ini mempengaruhi semua versi Access yang saat ini didukung oleh Microsoft (dari Access 2010 hingga 365).

bug ini telah diperbaiki.

  • Jika Anda menggunakan versi Office C2R (Klik untuk Menjalankan), gunakan "Perbarui sekarang" :
    • Access 2010 C2R: Diperbaiki dalam Build 7243.5000
    • Access 2013 C2R: Diperbaiki dalam Build 5197.1000
    • Akses 2016 C2R: Diperbaiki dalam Bangun 12130.20390
    • Akses 2019 (v1910): Diperbaiki dalam Build 12130.20390
    • Access 2019 (Volume License): Diperbaiki dalam Build 10353.20037
    • Saluran Bulanan Office 365: Diperbaiki dalam Bangun 12130.20390
    • Semi-Tahunan Office 365: Tetap dalam Bangun 11328.20480
    • Office 365 Semi-Tahunan Diperpanjang: Tetap dalam Bangun 10730.20422
    • Office 365 Ditargetkan Semi-Tahunan: Tetap dalam Bangun 11929.20494
  • Jika Anda menggunakan versi MSI Office, instal pembaruan yang cocok dengan versi Office Anda. Semua tambalan ini telah dirilis pada Pembaruan Microsoft, jadi menginstal semua Pembaruan Windows yang tertunda harus cukup:

Contoh

Berikut adalah contoh repro minimal:

  1. Buat database Access baru.
  2. Buat tabel baru, kosong "Table1" dengan bidang ID default dan bidang Long Integer "myint".
  3. Jalankan kode berikut di Jendela Langsung editor VBA:

    CurrentDb.Execute "UPDATE Table1 SET myint = 1 WHERE myint = 1"

Hasil yang diharapkan : Pernyataan berhasil diselesaikan.

Hasil aktual dengan salah satu pembaruan kereta diinstal: Terjadi galat run-time 3340 ("Kueri 'rusak").


Tautan yang berhubungan:

Heinzi
sumber
9
Posting ini tampaknya mengalami kesalahan yang sama menggunakan runtime Access 64-bit dan OLEDB. Hal-hal menakutkan, ini akan membuat banyak aplikasi yang menggunakan Access untuk menyimpan data tidak dapat digunakan.
Erik A
4
Saya baru saja memeriksa sistem dengan Office 2013 32-bit dan pada mesin tertentu UUID untuk pembaruan adalah 90150000-006E-0409-0000-0000000FF1CE... itu -0409-, tidak -0407-.
Gord Thompson
4
Saya baru saja memeriksa mesin lain di kantor yang memiliki Office 2013 64-bit dan UUID -006E-0409-juga. Kedua mesin memiliki Paket Layanan 1 untuk Microsoft Office 2013 (KB2850036) diinstal.
Gord Thompson
4
Untuk Office 2010 Pro Plus (SP2) kami perlu menggunakan {90140000-0011-0000-0000-0000000FF1CE}dalam skrip kumpulan. Perhatikan {9014...tidak{9114..}
AdamsTips
2
Saya telah ditambal dengan pembaruan resmi untuk menyelesaikan masalah tetapi saya masih mendapatkan kesalahan. Adakah yang punya masalah itu?
user218076
33

Solusi paling sederhana

Untuk pengguna saya, menunggu hampir sebulan hingga 10 Desember untuk rilis perbaikan dari Microsoft bukanlah suatu pilihan. Juga tidak mencopot pembaruan Microsoft yang melanggar di beberapa stasiun kerja yang dikunci oleh pemerintah.

Saya perlu menerapkan solusi, tetapi saya tidak senang dengan apa yang disarankan Microsoft - membuat dan mengganti kueri untuk setiap tabel.

Solusinya adalah mengganti nama Tabel dengan (SELECT * FROM Table)kueri sederhana langsung di UPDATEperintah. Ini tidak memerlukan membuat dan menyimpan satu ton permintaan tambahan, tabel, atau fungsi.

CONTOH:

Sebelum:

UPDATE Table1 SET Field1 = "x" WHERE (Field2=1);  

Setelah:

UPDATE (SELECT * FROM Table1) SET Field1 = "x" WHERE (Field2=1);  

Itu seharusnya lebih mudah diimplementasikan di beberapa basis data dan aplikasi (dan kemudian rollback).

Joe Marinucci
sumber
20

Ini bukan masalah pembaruan Windows, tetapi masalah yang diperkenalkan dengan rilis Office Patch Selasa November. Perubahan untuk memperbaiki kerentanan keamanan menyebabkan beberapa permintaan yang sah dilaporkan korup. Karena perubahan itu merupakan perbaikan keamanan, ini memengaruhi SEMUA unit Office, termasuk 2010, 2013, 2016, 2019, dan O365.

Bug telah diperbaiki di semua saluran, tetapi waktu pengiriman akan tergantung pada saluran yang Anda gunakan.

Untuk membangun Lisensi Volume MSI 2010, 2013, dan 2016, dan saluran Semi-tahunan O365, perbaikannya akan berada di build Selasa Patch Desember, 10 Desember. Untuk O365, Saluran Bulanan, dan Orang Dalam, ini akan diperbaiki ketika garpu Oktober dirilis, saat ini direncanakan untuk 24 November.

Untuk saluran Semi-Tahunan, bug diperkenalkan pada 11328.20468, yang dirilis 12 November, tetapi tidak menyebar ke semua orang sekaligus. Jika bisa, Anda mungkin ingin menunda pembaruan hingga 10 Desember.

Masalah terjadi untuk pembaruan kueri terhadap satu tabel dengan kriteria yang ditentukan (jadi jenis kueri lainnya tidak boleh terpengaruh, maupun kueri yang memperbarui semua baris tabel, atau kueri yang memperbarui kumpulan hasil kueri lain). Karena itu, solusi paling sederhana dalam kebanyakan kasus adalah mengubah kueri pembaruan untuk memperbarui kueri lain yang memilih semuanya dari tabel, daripada memperbarui kueri secara langsung.

Yaitu, jika Anda memiliki pertanyaan seperti:

UPDATE Table1 SET Table1.Field1 = "x" WHERE ([Table1].[Field2]=1);

Lalu, buat kueri baru (Kueri1) yang didefinisikan sebagai:

Select * from Table1;

dan perbarui kueri asli Anda ke:

UPDATE Query1 SET Query1.Field1 = "x" WHERE ([Query1].[Field2]=1);

Halaman resmi: Kesalahan akses: "Permintaan rusak"

Gustav
sumber
13
Apakah Anda benar-benar mengatakan dengan wajah lurus bahwa kita pergi ke 100-an ribu baris kode yang digunakan di beberapa aplikasi dan memperbaiki semua pembaruan sql yang secara sederhana memperbarui deretan data? Saya kira jika Anda menulis kueri baru hari ini, dan sekarang, solusi seperti itu mungkin. Tetapi untuk kode dan aplikasi yang ada gagasan bahwa pembaruan sql harus diubah tentu saja bukan pendekatan praktis untuk memecahkan masalah dengan cara apa pun.
Albert D. Kallal
5
@ AlbertD.Kallal, Anda harus tahu dari daftar MVP, bahwa saya hanya merujuk pada penjelasan untuk sumber masalah ini. Bagaimana menangani masalah ini benar-benar terserah Anda dan apa yang mungkin cocok dengan skenario Anda. Metode yang dijelaskan di sini hanyalah satu dari beberapa.
Gustav
1
@ AlbertD.Kallal Tidak boleh mengganti nama tabel dan membuat QueryDefs dengan nama tabel yang lama memperbaikinya? (Saya akan mengujinya dan memposting skrip jika berfungsi)
ComputerVersteher
Anda dapat melakukannya tanpa pemrograman, misalnya mengubah nama tabel "pengguna" menjadi "userst" dan kemudian membuat nama permintaan "pengguna" - dan kemudian itu akan bekerja tanpa kutukan pemrograman ....
Zvi Redler
9
@ AlbertD.Kallal: Saya berbagi rasa sakit Anda - jika ini adalah bug yang mempengaruhi perpustakaan runtime VC, saya tidak berpikir bahwa MS akan menunda perbaikan selama satu bulan dan menyarankan solusi "menulis ulang, mengkompilasi ulang dan memindahkan". (Agar adil, mereka memperbaiki dan merilis masalah VBA pada akhir Agustus dengan cepat.) Tapi jangan menembak pembawa pesan - Gustav tampaknya bukan karyawan MS. Mari berharap mereka mempertimbangkan kembali dan merilis tambalan sebelumnya; setelah semua, itu juga mempengaruhi aplikasi yang ditulis dalam bahasa lain yang kebetulan menggunakan mesin Access DB .
Heinzi
15

Untuk menyelesaikan sementara masalah ini tergantung pada versi Access yang digunakan:
Access 2010 Menghapus pembaruan KB4484127
Access 2013 Menghapus instalan pembaruan KB4484119
Access 2016 Menghapus instalasi pembaruan KB4484113
Akses 2019 JIKA DIPERLUKAN (tbc). Turunkan Versi dari Versi 1808 (Build 10352.20042) ke Versi 1808 (Build 10351.20054)
Office 365 ProPlus Downgrade dari Versi 1910 (Build 12130.20344) ke versi sebelumnya, lihat https://support.microsoft.com/en-gb/help/2770432/ how-to-revert-to-an-versi-sebelumnya-office-2013-or-office-2016-clic

Hibah
sumber
Saya mencopot pemasangannya, tetapi itu menginstal ulang saat saya memulai Windows berikutnya. Bagaimana Anda mencegahnya menginstal ulang?
dsteele
5
@dsteele Jika versi MSI dan tanpa WSUS, gunakan support.microsoft.com/en-us/help/3073930/... alat pemecahan masalah. Pada CTR nonaktifkan pembaruan di Office-Account-Settings ..
ComputerVersteher
5

Kami dan klien kami telah berjuang dengan ini dua hari terakhir dan akhirnya menulis makalah untuk membahas masalah ini secara rinci bersama dengan beberapa solusi: http://fmsinc.com/MicrosoftAccess/Errors/query_is_corrupt/

Ini mencakup temuan kami yang memengaruhi solusi Access saat menjalankan kueri pembaruan pada tabel lokal, tabel Access tertaut, dan bahkan tabel SQL Server yang ditautkan.

Ini juga memengaruhi solusi non-Microsoft Access menggunakan Access Database Engine (ACE) untuk tersambung ke database Access menggunakan ADO. Itu termasuk aplikasi Visual Studio (WinForm), aplikasi VB6, dan bahkan situs web yang memperbarui akses database pada mesin yang tidak pernah memiliki akses atau kantor diinstal pada mereka.

Kecelakaan ini bahkan dapat memengaruhi aplikasi Microsoft yang menggunakan ACE seperti PowerBI, Power Query, SSMA, dll. (Tidak dikonfirmasi), dan tentu saja, program lain seperti Excel, PowerPoint atau Word menggunakan VBA untuk mengubah database Access.

Selain penghapusan yang jelas dari Pembaruan Keamanan yang menyinggung, kami juga menyertakan beberapa opsi ketika tidak mungkin untuk menghapus karena izin atau distribusi aplikasi Access ke pelanggan eksternal yang PC-nya berada di luar kendali Anda. Itu termasuk mengubah semua kueri Pembaruan dan mendistribusikan aplikasi Access menggunakan Access 2007 (ritel atau runtime) karena versi itu tidak terpengaruh oleh pembaruan keamanan.

LukeChung-FMS
sumber
4

Gunakan modul berikut untuk secara otomatis mengimplementasikan solusi yang disarankan Microsoft (menggunakan kueri alih-alih tabel). Sebagai tindakan pencegahan, buat cadangan database Anda terlebih dahulu.

Gunakan AddWorkaroundForCorruptedQueryIssue()untuk menambahkan solusi dan RemoveWorkaroundForCorruptedQueryIssue()untuk menghapusnya kapan saja.

Option Compare Database
Option Explicit

Private Const WorkaroundTableSuffix As String = "_Table"

Public Sub AddWorkaroundForCorruptedQueryIssue()
    On Error Resume Next

    With CurrentDb
        Dim tableDef As tableDef
        For Each tableDef In .tableDefs
            Dim isSystemTable As Boolean
            isSystemTable = tableDef.Attributes And dbSystemObject

            If Not EndsWith(tableDef.Name, WorkaroundTableSuffix) And Not isSystemTable Then
                Dim originalTableName As String
                originalTableName = tableDef.Name

                tableDef.Name = tableDef.Name & WorkaroundTableSuffix

                Call .CreateQueryDef(originalTableName, "select * from [" & tableDef.Name & "]")

                Debug.Print "OldTableName/NewQueryName" & vbTab & "[" & originalTableName & "]" & vbTab & _
                            "NewTableName" & vbTab & "[" & tableDef.Name & "]"
            End If
        Next
    End With
End Sub

Public Sub RemoveWorkaroundForCorruptedQueryIssue()
    On Error Resume Next

    With CurrentDb
        Dim tableDef As tableDef
        For Each tableDef In .tableDefs
            Dim isSystemTable As Boolean
            isSystemTable = tableDef.Attributes And dbSystemObject

            If EndsWith(tableDef.Name, WorkaroundTableSuffix) And Not isSystemTable Then
                Dim originalTableName As String
                originalTableName = Left(tableDef.Name, Len(tableDef.Name) - Len(WorkaroundTableSuffix))

                Dim workaroundTableName As String
                workaroundTableName = tableDef.Name

                Call .QueryDefs.Delete(originalTableName)
                tableDef.Name = originalTableName

                Debug.Print "OldTableName" & vbTab & "[" & workaroundTableName & "]" & vbTab & _
                            "NewTableName" & vbTab & "[" & tableDef.Name & "]" & vbTab & "(Query deleted)"
            End If
        Next
    End With
End Sub

'From https://excelrevisited.blogspot.com/2012/06/endswith.html
Private Function EndsWith(str As String, ending As String) As Boolean
     Dim endingLen As Integer
     endingLen = Len(ending)
     EndsWith = (Right(Trim(UCase(str)), endingLen) = UCase(ending))
End Function

Anda dapat menemukan kode terbaru di repositori GitHub saya .

AddWorkaroundForCorruptedQueryIssue()akan menambahkan akhiran _Tableke semua tabel non-sistem, misalnya tabel IceCreamsakan diubah namanya menjadi IceCreams_Table.

Itu juga akan membuat kueri baru menggunakan nama tabel asli, yang akan memilih semua kolom dari tabel berganti nama. Dalam contoh kami, kueri akan diberi nama IceCreamsdan akan menjalankan SQL select * from [IceCreams_Table].

RemoveWorkaroundForCorruptedQueryIssue() melakukan tindakan sebaliknya.

Saya menguji ini dengan semua jenis tabel, termasuk tabel non-MDB eksternal (seperti SQL Server). Namun perlu diketahui, bahwa menggunakan kueri alih-alih tabel dapat menyebabkan kueri yang tidak dioptimalkan dijalankan terhadap database backend dalam kasus tertentu, terutama jika kueri asli Anda yang menggunakan tabel berkualitas baik atau sangat kompleks.

(Dan tentu saja, tergantung pada gaya pengkodean Anda, juga dimungkinkan untuk memecah hal-hal dalam aplikasi Anda. Jadi setelah memverifikasi bahwa perbaikan umumnya bekerja untuk Anda, tidak pernah merupakan ide yang buruk untuk mengekspor semua objek Anda sebagai teks dan menggunakan beberapa pengganti mencari sihir untuk memastikan bahwa setiap kejadian penggunaan nama tabel akan dijalankan terhadap kueri dan bukan tabel.)

Dalam kasus saya, memperbaiki ini bekerja sebagian besar tanpa efek samping, aku hanya perlu secara manual mengubah nama USysRibbons_Tablekembali ke USysRibbons, karena saya tidak ditandai sebagai tabel sistem ketika saya buat di masa lalu.

lauxjpn
sumber
Saya suka Anda menentukan tabel sistem dengan TableDef.Attributesdan menyalinnya ke jawaban saya;) dan fungsi undo adalah ide yang bagus (tapi nama lama dan baru harus disimpan dalam sebuah tabel karena tergantung pada tidak ada tabel dengan akhiran sebelum nama diubah). Beberapa bagian lainnya rusak (mis. Tabel dapat diakhiri dengan akhiran atau nama baru sudah digunakan atau On Error Resume Nexttanpa menangani kesalahan nanti). Apakah Anda tahu RubberduckVBA ? Addin ini dapat memeriksa kode Anda dan membuat saran yang bagus untuk perbaikan, di samping semua fitur lainnya.
ComputerVersteher
Dan Anda harus menunjukkan bug yang dapat disebabkan oleh pendekatan kami (Lihat komentar @Erics tentang jawaban saya)
ComputerVersteher
Ah, saya tidak melihat bahwa sudah ada jawaban yang sama di sini, jadi terima kasih untuk ulasannya! Suffix didefinisikan dalam konstanta sendiri, sehingga dapat dengan mudah diubah jika ada objek yang sudah ada sebelumnya yang sudah menggunakan suffix. Kalau tidak, skrip berfungsi sebagaimana mestinya tetapi siapa pun harus merasa terdorong untuk memodifikasinya sesuai kebutuhan masing-masing. Script telah diuji pada proyek yang cukup besar (400+ tabel) termasuk tabel eksternal / tertaut ke berbagai sumber basis data eksternal. Saya tidak tahu tentang Rubberduck (hanya tentang MZ-Tools). Saya pasti akan memeriksanya!
lauxjpn
3

Bagi mereka yang ingin mengotomatiskan proses ini melalui PowerShell , berikut adalah beberapa tautan yang saya temukan yang mungkin membantu:

Deteksi dan Hapus Pembaruan yang Menyinggung

Ada skrip PowerShell yang tersedia di sini https://www.arcath.net/2017/09/office-update-remover yang mencari registri untuk pembaruan Office tertentu (disahkan sebagai nomor kb) dan menghapusnya menggunakan panggilan untuk msiexec.exe. Script ini mem-parsing kedua GUID dari kunci registri untuk membangun perintah untuk menghapus pembaruan yang sesuai.

Satu perubahan yang saya sarankan akan menggunakan /REBOOT=REALLYSUPPRESSseperti yang dijelaskan dalam Cara menghapus KB4011626 dan pembaruan Office lainnya (Referensi tambahan: https://docs.microsoft.com/en-us/windows/win32/msi/uninstalling-patches ). Baris perintah yang Anda bangun terlihat seperti ini:

msiexec /i {90160000-0011-0000-0000-0000000FF1CE} MSIPATCHREMOVE={9894BF35-19C1-4C89-A683-D40E94D08C77} /qn REBOOT=REALLYSUPPRESS

Perintah untuk menjalankan skrip akan terlihat seperti ini:

OfficeUpdateRemover.ps1 -kb 4484127

Cegah Pembaruan Tidak Menginstal

Pendekatan yang disarankan di sini tampaknya menyembunyikan pembaruan . Jelas ini dapat dilakukan secara manual, tetapi ada beberapa skrip PowerShell yang dapat membantu dengan otomatisasi. Link ini: https://www.maketecheasier.com/hide-updates-in-windows-10/ menjelaskan proses secara rinci, tapi saya akan meringkas di sini.

  1. Instal Modul Pembaruan PowerShell Windows .
  2. Gunakan perintah berikut untuk menyembunyikan pembaruan berdasarkan nomor KB:

    Hide-WUUpdate -KBArticleID KB4484127

Semoga ini bisa membantu orang lain di luar sana.

AdamsTips
sumber
3

VBA-Script untuk MS-Workaround:

Disarankan untuk menghapus pembaruan kereta, jika mungkin (jika tidak coba kode saya), setidaknya untuk Versi MSI. Lihat jawaban https://stackoverflow.com/a/58833831/9439330 .

Untuk Versi CTR (Klik untuk Menjalankan), Anda harus menghapus semua Pembaruan November Kantor, apa yang dapat menyebabkan masalah keamanan serius (tidak yakin apakah ada perbaikan kritis yang akan dihapus).

Dari komentar @ Eric:

  • Jika Anda menggunakan Table.Tablenameuntuk mengikat formulir, mereka tidak terikat karena nama tabel sebelumnya sekarang menjadi nama-permintaan !.
  • OpenRecordSet(FormerTableNowAQuery, dbOpenTable) akan gagal (karena kueri sekarang, bukan tabel lagi)

Peringatan! Cukup cepat diuji terhadap Northwind.accdb di Office 2013 x86 CTR Tidak Ada Garansi!

Private Sub RenameTablesAndCreateQueryDefs()
With CurrentDb
    Dim tdf As DAO.TableDef
    For Each tdf In .TableDefs

        Dim oldName As String
        oldName = tdf.Name

        If Not (tdf.Attributes And dbSystemObject) Then 'credit to @lauxjpn for better check for system-tables
            Dim AllFields As String
            AllFields = vbNullString

            Dim fld As DAO.Field

            For Each fld In tdf.Fields
                AllFields = AllFields & "[" & fld.Name & "], "
            Next fld

            AllFields = Left(AllFields, Len(AllFields) - 2)
            Dim newName As String
            newName = oldName

            On Error Resume Next
            Do
                Err.Clear
                newName = newName & "_"
                tdf.Name = newName
            Loop While Err.Number = 3012
            On Error GoTo 0

            Dim qdf As DAO.QueryDef

            Set qdf = .CreateQueryDef(oldName)
            qdf.SQL = "SELECT " & AllFields & " FROM [" & newName & "]"
        End If
    Next
    .TableDefs.Refresh

End With
End Sub

Untuk pengujian:

Private Sub TestError()
With CurrentDb
    .Execute "Update customers Set City = 'a' Where 1=1", dbFailOnError 'works

    .Execute "Update customers_ Set City = 'b' Where 1=1", dbFailOnError 'fails
End With
End Sub
ComputerVersteher
sumber
4
Perhatikan bahwa solusi ini akan merusak subformulir yang terikat ke tabel (perlu direbahkan ke kueri) dan kode yang bekerja dengan tabledef dengan nama tabel yang di-hardcode. Gunakan dengan sangat hati-hati, kemungkinan ini hanya memperbaiki satu bug untuk membuat dua bug baru tergantung pada apa yang sedang dilakukan aplikasi Anda.
Erik A
@ ErikA Tentu saja hanya solusi, tapi saya bisa mengikat Inventory to reorder Subform for Homeke bentuk Inventorytabel Home, tanpa masalah. Bahkan tidak disarankan untuk mengikat formulir ke kueri alih-alih tabel (tidak mengikat seperti tabel Select * From table?).
ComputerVersteher
2
Jika saya mengikat subformulir ke tabel, saya biasanya melakukannya menggunakan Table.TableNamenotasi. Jika Anda melakukannya SELECT * FROM TableName, tentu saja Anda baik-baik saja. Tetapi jika Anda menggunakan Table.TableName, subformulir Anda akan menjadi tidak terikat jika Anda mengganti nama tabel.
Erik A
@ ErikA: Itu benar. Adakah manfaat dengan melakukan itu?
ComputerVersteher
3
Tidak sejauh yang saya tahu, kecuali bahwa itu lebih singkat. Ada keuntungan substansial dari TableDefs!MyTableName.OpenRecordset(dbOpenTable), (dukungan pencarian indeks), yang saya juga cenderung menggunakan dan juga akan menyebabkan kesalahan dengan pendekatan Anda
Erik A
2

Saya mengganti currentDb.Executedan Docmd.RunSQLdengan fungsi pembantu. Itu bisa pra-proses dan mengubah Pernyataan SQL jika ada pernyataan pembaruan hanya berisi satu tabel. Saya sudah memiliki dualtabel (baris tunggal, kolom tunggal) jadi saya pergi dengan opsi fakeTable.

Catatan : Ini tidak akan mengubah objek kueri Anda. Ini hanya akan membantu eksekusi SQL melalui VBA.If you would like to change your query objects, use FnQueryReplaceSingleTableUpdateStatements and update your sql in each of your querydefs. Shouldn't be a problem either.

Ini hanya sebuah konsep (If it's a single table update modify the sql before execution). Sesuaikan sesuai kebutuhan Anda. Metode ini tidak membuat kueri pengganti untuk setiap tabel (yang mungkin merupakan cara termudah tetapi memiliki kekurangannya sendiri. Yaitu masalah kinerja)

+ Poin: Anda dapat terus menggunakan bantuan ini bahkan setelah MS memperbaiki bug itu tidak akan mengubah apa pun. Dalam hal, masa depan membawa masalah lain, Anda siap untuk pre-processSQL Anda di satu tempat. Saya tidak menggunakan metode pembaruan pemutakhiran karena itu membutuhkan akses Admin + akan memakan waktu terlalu lama untuk membuat semua orang di versi yang benar + bahkan jika Anda menghapus, beberapa kebijakan kelompok pengguna akhir menginstal pembaruan terbaru lagi. Anda kembali ke masalah yang sama.

Jika Anda memiliki akses ke kode sumber, use this methoddan Anda 100% yakin bahwa tidak ada pengguna akhir yang mengalami masalah.

Public Function Execute(Query As String, Optional Options As Variant)
    'Direct replacement for currentDb.Execute

    If IsBlank(Query) Then Exit Function

    'invalid db options remove
    If Not IsMissing(Options) Then
        If (Options = True) Then
            'DoCmd RunSql query,True ' True should fail so transactions can be reverted
            'We are only doing this so DoCmd.RunSQL query, true can be directly replaced by helper.Execute query, true.
            Options = dbFailOnError
        End If
    End If

    'Preprocessing the sql command to remove single table updates
    Query = FnQueryReplaceSingleTableUpdateStatements(Query)

    'Execute the command
    If ((Not IsMissing(Options)) And (CLng(Options) > 0)) Then
        currentDb.Execute Query, Options
    Else
        currentDb.Execute Query
    End If

End Function

Public Function FnQueryReplaceSingleTableUpdateStatements(Query As String) As String
    ' ON November 2019 Microsoft released a buggy security update that affected single table updates.
    '/programming/58832269/getting-error-3340-query-is-corrupt-while-executing-queries-docmd-runsql

    Dim singleTableUpdate   As String
    Dim tableName           As String

    Const updateWord        As String = "update"
    Const setWord           As String = "set"

    If IsBlank(Query) Then Exit Function

    'Find the update statement between UPDATE ... SET
    singleTableUpdate = FnQueryContainsSingleTableUpdate(Query)

    'do we have any match? if any match found, that needs to be preprocessed
    If Not (IsBlank(singleTableUpdate)) Then

        'Remove UPDATe keyword
        If (VBA.Left(singleTableUpdate, Len(updateWord)) = updateWord) Then
            tableName = VBA.Right(singleTableUpdate, Len(singleTableUpdate) - Len(updateWord))
        End If

        'Remove SET keyword
        If (VBA.Right(tableName, Len(setWord)) = setWord) Then
            tableName = VBA.Left(tableName, Len(tableName) - Len(setWord))
        End If

        'Decide which method you want to go for. SingleRow table or Select?
        'I'm going with a fake/dual table.
        'If you are going with update (select * from T) as T, make sure table aliases are correctly assigned.
        tableName = gDll.sFormat("UPDATE {0},{1} SET ", tableName, ModTableNames.FakeTableName)

        'replace the query with the new statement
        Query = vba.Replace(Query, singleTableUpdate, tableName, compare:=vbDatabaseCompare, Count:=1)

    End If

    FnQueryReplaceSingleTableUpdateStatements = Query

End Function

Public Function FnQueryContainsSingleTableUpdate(Query As String) As String
    'Returns the update ... SET statment if it contains only one table.

    FnQueryContainsSingleTableUpdate = ""
    If IsBlank(Query) Then Exit Function

    Dim pattern     As String
    Dim firstMatch  As String

    'Get the pattern from your settings repository or hardcode it.
    pattern = "(update)+(\w|\s(?!join))*set"

    FnQueryContainsSingleTableUpdate = FN_REGEX_GET_FIRST_MATCH(Query, pattern, isGlobal:=True, isMultiline:=True, doIgnoreCase:=True)

End Function

Public Function FN_REGEX_GET_FIRST_MATCH(iText As String, iPattern As String, Optional isGlobal As Boolean = True, Optional isMultiline As Boolean = True, Optional doIgnoreCase As Boolean = True) As String
'Returns first match or ""

    If IsBlank(iText) Then Exit Function
    If IsBlank(iPattern) Then Exit Function

    Dim objRegex    As Object
    Dim allMatches  As Variant
    Dim I           As Long

    FN_REGEX_GET_FIRST_MATCH = ""

   On Error GoTo FN_REGEX_GET_FIRST_MATCH_Error

    Set objRegex = CreateObject("vbscript.regexp")
    With objRegex
        .Multiline = isMultiline
        .Global = isGlobal
        .IgnoreCase = doIgnoreCase
        .pattern = iPattern

        If .test(iText) Then
            Set allMatches = .Execute(iText)
            If allMatches.Count > 0 Then
                FN_REGEX_GET_FIRST_MATCH = allMatches.item(0)
            End If
        End If
    End With

    Set objRegex = Nothing

   On Error GoTo 0
   Exit Function

FN_REGEX_GET_FIRST_MATCH_Error:
    FN_REGEX_GET_FIRST_MATCH = ""

End Function

Sekarang CTRL+F

Cari dan ganti docmd.RunSQLdenganhelper.Execute

Cari dan ganti [currentdb|dbengine|or your dbobject].executedenganhelper.execute

Selamat bersenang-senang!

Krish
sumber
0

Ok, saya juga akan berpadu di sini, karena meskipun bug ini sudah diperbaiki, perbaikan itu belum terisi penuh melalui berbagai perusahaan di mana pengguna akhir mungkin tidak dapat memperbarui (seperti majikan saya ...)

Ini solusi untuk saya DoCmd.RunSQL "UPDATE users SET uname= 'bob' WHERE usercode=1". Cukup komentari permintaan yang menyinggung dan masukkan kode di bawah ini.

    'DoCmd.RunSQL "UPDATE users SET uname= 'bob' WHERE usercode=1"
    Dim rst As DAO.Recordset
    Set rst = CurrentDb.OpenRecordset("users")
    rst.MoveLast
    rst.MoveFirst
    rst.FindFirst "[usercode] = 1" 'note: if field is text, use "[usercode] = '1'"
    rst.Edit
    rst![uname] = "bob"
    rst.Update
    rst.Close
    Set rst = Nothing

Saya tidak bisa mengatakan itu cantik, tapi itu menyelesaikan pekerjaan.

Desain kacau
sumber