DoCmd.RunSQL sorguları yürütülürken 3340 Sorgu Hatası '' alınıyor


83

KB 4484127'yi çözen Office 2010 için Windows güncelleştirmesini yükledikten sonra bir WHERE yan tümcesi içeren sorgular yürütürken bir hata alıyorum.

Örneğin, bu sorguyu yürütmek:

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

Bu hatanın sonuçları:

Hata numarası = 3340 Sorgu '' bozuk

Söz konusu güncelleme şu anda yüklü:

Microsoft Office 2010 Service Pack 2 güncelleştirmesi 448127'yi gösteren ekran görüntüsü

Sorgularımı başarıyla nasıl çalıştırabilirim? Bu güncellemeyi kaldırmalı mıyım?

Yanıtlar:


92

özet

Bu, 12 Kasım 2019'da yayımlanan Office güncelleştirmelerinin neden olduğu bilinen bir hatadır . Hata, şu anda Microsoft tarafından desteklenen Access'in tüm sürümlerini (Access 2010'dan 365'e) etkiler.

Bu hata giderildi.

  • Office'in bir C2R (Tıkla-Çalıştır) sürümünü kullanıyorsanız, "Şimdi güncelle" seçeneğini kullanın :
    • Access 2010 C2R: Build 7243.5000'de Sabit
    • Access 2013 C2R: Yapı 5197.1000'de Sabit
    • Access 2016 C2R: 12130.20390 Yapısında Sabit
    • Access 2019 (v1910): 12130.20390 Yapısında Sabit
    • Access 2019 (Toplu Lisans): Derleme 10353.20037'de düzeltildi
    • Office 365 Aylık Kanal: Derleme 12130.20390'da düzeltildi
    • Office 365 Altı Aylık: Derleme 11328.20480'de düzeltildi
    • Office 365 Altı Aylık Genişletilmiş: Derleme 10730.20422'de düzeltildi
    • Office 365 Altı Aylık Hedeflenen: Yapıda Sabit 11929.20494
  • Office'in MSI sürümünü kullanıyorsanız, Office sürümünüzle eşleşen güncelleştirmeyi yükleyin. Bu düzeltme eklerinin tümü Microsoft Update'te yayımlanmıştır, bu nedenle bekleyen tüm Windows Güncelleştirmelerini yüklemek yeterli olacaktır:

Misal

İşte minimal bir repro örneği:

  1. Yeni bir Access veritabanı oluşturun.
  2. Varsayılan kimlik alanı ve Uzun Tamsayı alanı "myint" ile yeni, boş bir tablo "Table1" oluşturun.
  3. VBA düzenleyicisinin Anlık Penceresinde aşağıdaki kodu yürütün:

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

Beklenen sonuç : Deyim başarıyla tamamlandı.

Yüklü buggy güncellemelerinden biri ile gerçek sonuç : Çalışma zamanı hatası 3340 oluşur ("Sorgu '' bozuk").


İlgili Bağlantılar:


9
Bu yazı 64 bit Access çalışma zamanı ve OLEDB kullanarak aynı hatayla karşılaşıyor gibi görünüyor. Korkunç şeyler, bu verileri kullanmak için Access'i kullanan birçok uygulamayı kullanılamaz hale getirir.
Erik A

4
Office 2013 32 bit ile bir sistemi kontrol ettim ve o makinede güncelleme için UUID 90150000-006E-0409-0000-0000000FF1CE... bu -0409-değil -0407-.
Gord Thompson

4
Ofiste Office 2013 64-bit'e sahip başka bir makineyi kontrol ettim ve UUID -006E-0409-de var. Her iki makinede de Microsoft Office 2013 için Service Pack 1 (KB2850036) yüklü.
Gord Thompson

4
Office 2010 Pro Plus (SP2) {90140000-0011-0000-0000-0000000FF1CE}için toplu komut dosyasında kullanmamız gerekiyordu . Not {9014...not{9114..}
AdamsTips

2
Sorunu çözmek için resmi güncellemeyle yamalı ama yine de hatayı alıyorum. Başkasının bu problemi var mı?
user218076

33

En Basit Çözüm

Kullanıcılarım için, 10 Aralık'a kadar Microsoft'tan düzeltme yayınlanması için yaklaşık bir ay beklemek bir seçenek değil. Hükümet kilitli iş istasyonlarında rahatsız edici Microsoft güncelleştirmesini de kaldırmıyor.

Bir geçici çözüm uygulamak gerekir, ancak tam olarak ne Microsoft önerilen - heyecan ve oluşturma ve her tablo için bir sorgu yerine ile değil.

Çözüm, Tablo adını (SELECT * FROM Table)doğrudan UPDATEkomutta basit bir sorgu ile değiştirmektir . Bu, tonlarca ek sorgu, tablo veya işlev oluşturmayı ve kaydetmeyi gerektirmez.

MİSAL:

Önce:

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

Sonra:

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

Bu, çeşitli veritabanları ve uygulamalar (ve daha sonra geri alma) genelinde uygulanması çok daha kolay olmalıdır.


20

Bu bir Windows güncelleme sorunu değil, Kasım Yaması Salı Ofisi sürümünde ortaya çıkan bir sorun. Güvenlik açığını gidermek için yapılan bir değişiklik, bazı meşru sorguların bozuk olarak bildirilmesine neden olur. Değişiklik bir güvenlik düzeltmesi olduğundan, 2010, 2013, 2016, 2019 ve O365 dahil olmak üzere TÜM Office yapılarını etkiler.

Hata tüm kanallarda düzeltildi, ancak yayınlanma süresi hangi kanalda olduğunuza bağlı olacaktır.

2010, 2013 ve 2016 MSI ve 2019 Toplu Lisans sürümleri ve O365 Yarı Yıllık kanalı için düzeltme, 10 Aralık Salı günü Aralık 10'da olacak. O365, Aylık Kanal ve Insider'lar için bu düzeltilecek Ekim çatalı piyasaya sürüldüğünde, şu anda 24 Kasım için planlanıyor.

Yarı Yıllık kanal için, hata 12 Kasım'da yayınlanan 11328.20468'de tanıtıldı, ancak aynı anda herkese yayılmadı. Yapabiliyorsanız, 10 Aralık tarihine kadar güncellemeyi beklemeye isteyebilirsiniz.

Sorun, belirtilen ölçütlere sahip tek bir tablodaki güncelleştirme sorguları için geçerlidir (bu nedenle diğer sorgu türleri etkilenmemeli veya bir tablonun tüm satırlarını güncelleştiren herhangi bir sorgu veya başka bir sorgunun sonuç kümesini güncelleştiren bir sorgu). Bununla birlikte, çoğu durumda en basit çözüm, sorguyu doğrudan güncellemek yerine, tablodan her şeyi seçen başka bir sorguyu güncellemek için güncelleme sorgusunu değiştirmektir.

Yani, aşağıdaki gibi bir sorunuz varsa:

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

Ardından, şu şekilde tanımlanan yeni bir sorgu (Sorgu1) oluşturun:

Select * from Table1;

ve orijinal sorgunuzu şuna güncelleyin:

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

Resmi sayfa: Erişim hatası: "Sorgu bozuk"


13
Aslında düz bir yüzle, birden fazla uygulamada dağıtılan 100 bin satırlık kodlara gittiğimizi ve bir satır veriyi güncelleyen tüm sql güncellemelerini düzelttiğimizi mi söylüyorsunuz? Bugün yeni bir sorgu yazıyorsanız ve şu anda böyle bir geçici çözüm mümkündür. Ancak mevcut kod ve uygulamalar için sql güncellemelerinin değiştirileceği fikri elbette, probelm çözümüne herhangi bir şekilde pratik bir yaklaşım değildir.
Albert D. Kallal

5
@ AlbertD.Kallal, MVP listesinden bilmelisiniz, sadece sorunun kaynağı için açıklamaya başvuruyorum. Sorunla nasıl başa çıkacağınız tamamen size bağlıdır ve senaryonuza neyin uygun olabileceği. Burada açıklanan yöntem birkaç yöntemden sadece biridir.
Gustav

1
@ AlbertD.Kallal Tabloları yeniden adlandırmamalı ve eski tablo adıyla QueryDefs oluşturmamalı mı? (Bunu test edip çalışırsa senaryoyu gönderirim)
ComputerVersteher

Programlama olmadan yapabilirsiniz, örneğin tablo "kullanıcıları" yeniden "userst" olarak yeniden adlandırın ve sonra "users" sorgu adı oluşturun - ve sonra hiçbir programlama chane ile çalışacaktır ....
Zvi Redler

9
@ AlbertD.Kallal: Acınızı paylaşıyorum - bu VC çalışma zamanı kitaplığını etkileyen bir hata olsaydı, MS'in düzeltmeyi bir ay geciktireceğini ve "yeniden yazma, yeniden derleme ve yeniden konuşlandırma" geçici çözüm önerdiğini düşünmüyorum. (Adil olmak gerekirse, Ağustos ayı sonlarında VBA sorununu hızlı bir şekilde çözdüler ve yayınladılar.) Ancak elçiyi vurmayalım - Gustav bir MS çalışanı gibi görünmüyor. Umarız daha önce bir yamayı yeniden düşünürler ve yayınlarlar; sonuçta , Access DB motorunu kullanan diğer dillerde yazılmış uygulamaları da etkiler .
Heinzi

15

Bu sorunu geçici olarak çözmek için kullanılan Access sürümüne bağlıdır:
Access 2010 Kaldırma güncelleştirmesi KB4484127
Access 2013 Kaldırma güncelleştirmesi KB4484119
Access 2016 Kaldırma güncelleştirmesi KB4484113
Access 2019 GEREKİYORSA (tbc). Sürüm 1808'den (Derleme 10352.20042) Sürüm 1808'e (Derleme 10351.20054)
düşürme Office 365 ProPlus Sürüm 1910'dan (Derleme 12130.20344) önceki bir sürüme yükseltme, bkz. Https://support.microsoft.com/en-gb/help/2770432/ nasıl yapılır-geri almadan-to-bir-eski sürüm işyeri-2013-veya-ofis-2016-clic


Kaldırdım, ancak Windows'u bir sonraki başlatışımda yeniden yüklendi. Yeniden yüklenmesini nasıl önlersiniz?
dsteele

5
@dsteele MSI sürümü varsa ve WSUS yoksa, support.microsoft.com/en-us/help/3073930/… sorun giderme aracını kullanın. TO'da Office-Hesap-Ayarları'ndaki güncellemeleri devre dışı
ComputerVersteher

5

Biz ve müşterilerimiz son iki gündür bununla mücadele ettik ve nihayet konuyu bazı çözümlerle birlikte ayrıntılı olarak tartışmak için bir makale yazdık: http://fmsinc.com/MicrosoftAccess/Errors/query_is_corrupt/

Yerel tablolarda, bağlı Erişim tablolarında ve hatta bağlı SQL Server tablolarında güncelleme sorguları çalıştırırken Access çözümlerini etkilediğine dair bulgularımızı içerir.

Ayrıca ADO kullanarak Access veritabanlarına bağlanmak için Access Veritabanı Altyapısı'nı (ACE) kullanan Microsoft dışı çözümleri de etkiler. Buna, Visual Studio (WinForm) uygulamaları, VB6 uygulamaları ve hatta daha önce Access veya Office yüklü olmayan makinelerde Access veritabanlarını güncelleyen web siteleri de dahildir.

Bu çökme, PowerBI, Power Query, SSMA, vb. (Onaylanmadı) gibi ACE kullanan Microsoft uygulamalarını ve elbette Access veritabanlarını değiştirmek için VBA kullanan Excel, PowerPoint veya Word gibi diğer programları bile etkileyebilir.

Sorunlu Güvenlik Güncellemelerinin açıkça kaldırılmasına ek olarak, Access uygulamalarının izinleri veya PC'leri kontrolünüz dışında olan harici müşterilere dağıtılması nedeniyle kaldırmanın mümkün olmadığı durumlarda da bazı seçenekler ekliyoruz. Bu, tüm Güncelleştirme sorgularını değiştirmeyi ve Access uygulamalarını (perakende veya çalışma zamanı) kullanarak Access uygulamalarını dağıtmayı içerir, çünkü bu sürüm güvenlik güncelleştirmelerinden etkilenmez.


4

Microsofts tarafından önerilen geçici çözümü otomatik olarak uygulamak için aşağıdaki modülü kullanın (tablo yerine sorgu kullanarak). Önlem olarak, önce veritabanınızı yedekleyin.

AddWorkaroundForCorruptedQueryIssue()Geçici çözümü eklemek ve RemoveWorkaroundForCorruptedQueryIssue()istediğiniz zaman kaldırmak için kullanın .

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

En son kodu GitHub veri havuzumda bulabilirsiniz .

AddWorkaroundForCorruptedQueryIssue()soneki _Tablesistem olmayan tüm tablolara ekler , örneğin tablo IceCreamsyeniden adlandırılır IceCreams_Table.

Ayrıca, yeniden adlandırılan tablonun tüm sütunlarını seçecek olan orijinal tablo adını kullanarak yeni bir sorgu oluşturur. Örneğimizde, sorgu adlandırılır IceCreamsve SQL yürütülür select * from [IceCreams_Table].

RemoveWorkaroundForCorruptedQueryIssue() ters işlemleri yapar.

Bu harici MDB olmayan tablolar (SQL Server gibi) dahil her türlü tablo ile test. Ancak, bir tablo yerine bir sorgu kullanmanın, özellikle tabloları kullanan orijinal sorgularınız düşük kalitede veya çok karmaşıksa, belirli durumlarda bir arka uç veritabanına karşı optimize edilmemiş sorguların yürütülmesine neden olabileceğini unutmayın.

(Ve elbette, kodlama stilinize bağlı olarak, uygulamanızdaki şeyleri kırmak da mümkündür. Bu nedenle, düzeltmenin genellikle sizin için çalıştığını doğruladıktan sonra, tüm nesnelerinizi metin olarak dışa aktarmak ve bazı bul değiştirme işlevlerini kullanmak asla kötü bir fikir değildir Tablo adlarının kullanımının herhangi bir örneğinin tablolara değil sorgulara karşı çalıştırılmasını sağlamak için büyü.)

Benim durumumda, bu düzeltme, büyük ölçüde herhangi bir yan etki olmaksızın, sadece el ile yeniden adlandırmak için gerekli işleri USysRibbons_Tablegeri USysRibbonsGeçmişte oluşturulduğu zaman bir sistem tablo olarak işaretlemiş olmasaydı gibi.


Ben TableDef.Attributesbir sistem tablo belirleme gibi ve benim cevap kopyalayın;) ve geri alma işlevi iyi bir fikirdir (ancak eski ve yeni ad, yeniden adlandırma önce sonek tablo yok bağlı olarak bir tabloda depolanmalıdır). Diğer bazı bölümler arızalıdır (örn. Tablolar sonekle bitebilir veya yeni ad zaten kullanılıyor veya On Error Resume Nextdaha sonra hata işlemeden). Biliyor musunuz RubberduckVBA ? Bu Addin, kodunuzu inceleyebilir ve diğer tüm özelliklerin yanı sıra iyileştirme için güzel önerilerde bulunabilir.
ComputerVersteher

Ve yaklaşımımızın neden olabileceği hataları göstermelisiniz (Cevabımdaki @Erics yorumlarına bakın)
ComputerVersteher

Ah, burada zaten benzer bir cevap olduğunu görmedim, bu yüzden inceleme için teşekkürler! Son ek kendi sabitinde tanımlanır, bu nedenle son eki zaten kullanan önceden var olan önceden tanımlanmış bir nesne olması durumunda kolayca değiştirilebilir. Aksi takdirde senaryo olduğu gibi çalışır, ancak herkes onu kişisel ihtiyaçlarına göre değiştirmeye teşvik edilmelidir. Komut dosyası, farklı harici veritabanı kaynaklarına harici / bağlantılı tablolar da dahil olmak üzere oldukça büyük projelerde (400+ tablo) test edilmiştir. Rubberduck hakkında bilmiyordum (sadece MZ-Tools hakkında). Kesinlikle onları kontrol edecek!
lauxjpn

3

Bu işlemi PowerShell ile otomatikleştirmek isteyenler için , yararlı olabileceğini düşündüğüm birkaç bağlantı var:

Sorunlu Güncellemeleri Algıla ve Kaldır

Burada bir PowerShell betiği bulunmaktadır. Https://www.arcath.net/2017/09/office-update-remover , belirli bir Office güncelleştirmesini (kb numarası olarak iletilir) arar ve bir çağrı kullanarak kaldırır. msiexec.exe. Bu komut dosyası, uygun güncelleştirmeyi kaldırma komutunu oluşturmak için her iki GUID'i de kayıt defteri anahtarlarından ayrıştırır.

Önereceğim bir değişiklik, KB4011626 nasıl kaldırılır ve diğer Office güncelleştirmeleri (Ek başvuru: https://docs.microsoft.com/en-us/windows/win32/msi/uninstal-patches ) /REBOOT=REALLYSUPPRESSbölümünde anlatıldığı gibi kullanmak olacaktır . Oluşturduğunuz komut satırı şöyle görünür:

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

Komut dosyasını çalıştırma komutu şuna benzer:

OfficeUpdateRemover.ps1 -kb 4484127

Güncelleştirmelerin Yüklenmesini Önleme

Burada önerilen yaklaşım güncellemeyi gizliyor gibi görünüyor . Açıkçası bu manuel olarak yapılabilir, ancak otomasyona yardımcı olabilecek bazı PowerShell komut dosyaları vardır. Bu bağlantı: https://www.maketecheasier.com/hide-updates-in-windows-10/ süreci ayrıntılı olarak açıklar, ancak burada özetleyeceğim.

  1. Windows Update PowerShell Modülünü yükleyin .
  2. KB numarasına göre bir güncellemeyi gizlemek için aşağıdaki komutu kullanın:

    Hide-WUUpdate -KBArticleID KB4484127

Umarım bu başka birine yardım eder.


3

MS-Geçici Çözüm için VBA-Script:

En azından MSI Sürümleri için, mümkünse buggy güncellemesinin kaldırılması önerilir (kodumu denemezseniz). Bkz. Cevap https://stackoverflow.com/a/58833831/9439330 .

TO (Tıkla-Çalıştır) Sürümlerinde, ciddi güvenlik sorunlarına neden olabilecek tüm Office Kasım Güncellemelerini kaldırmanız gerekir (kritik düzeltmelerin kaldırılıp kaldırılmayacağından emin değilsiniz).

@ Eric'in yorumlarından:

  • Table.TablenameFormları bağlamak için kullanırsanız , eski tablo-adı artık bir sorgu-adı!
  • OpenRecordSet(FormerTableNowAQuery, dbOpenTable) başarısız olacaktır (artık bir sorgu olduğu için, artık bir tablo değil)

Dikkat! Office 2013 x86 TO'sunda Northwind.accdb'ye karşı hızlı bir şekilde test edildi Garanti Yok!

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

Test için:

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

4
Bu geçici çözüm, tablolara bağlı alt formları (sorgulara ribaund olması gerekir) ve sabit kodlu tablo adıyla tabledefs ile çalışan kodları bozacağına dikkat edin. Büyük bir dikkatle kullanın, oranlar, uygulamanızın ne yaptığına bağlı olarak sadece iki yeni hata oluşturmak için bir hatayı düzeltir.
Erik A

@ErikA ders sadece geçici bir çözüm ki, ama bağlayabilir Inventory to reorder Subform for Homeiçin Inventorytablonun Homesorunsuz, form. Hatta formları tablolar yerine sorgulara bağlamak tavsiye edilmez (tabloya bağlanma gibi değil Select * From tablemi?).
ComputerVersteher

2
Bir alt formu bir tabloya bağlarsam, genellikle Table.TableNamegösterimi kullanarak yaparım . Bunu yaparsanız SELECT * FROM TableNamebunun yerine, ders ceza konum. Ancak kullanırsanız Table.TableName, tabloyu yeniden adlandırırsanız alt formunuz ilişkisiz hale gelir.
Erik A

@ErikA: Bu doğru. Bunu yaparak herhangi bir faydası var mı?
ComputerVersteher

3
Bildiğim kadarıyla değil, daha kısa olması dışında. Yine TableDefs!MyTableName.OpenRecordset(dbOpenTable)de kullanma eğiliminde olduğum ve aynı zamanda yaklaşımınızla ilgili hatalara neden olacağım (indeks arama desteği) önemli bir avantajı var
Erik A

2

Ben yerini currentDb.Executeve Docmd.RunSQLbir yardımcı fonksiyonu ile. Herhangi bir güncelleme deyimi yalnızca bir tablo içeriyorsa, bu SQL deyimini önceden işleyebilir ve değiştirebilir. Ben zaten dualbir fakeTable seçeneği ile gittim (tek satır, tek sütun) tablo var.

Not : Bu, sorgu nesnelerinizi değiştirmez. Yalnızca VBA aracılığıyla SQL yürütmelerine yardımcı olacaktır.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.

Bu sadece bir kavram (If it's a single table update modify the sql before execution). Gereksinimlerinize göre uyarlayın. Bu yöntem her tablo için yedek sorgular oluşturmaz (en kolay yol olabilir, ancak kendi dezavantajları vardır. Performans sorunları)

+ Puanlar: Bu hatayı MS hata düzelttikten sonra bile hiçbir şey değişmez kullanmaya devam edebilirsiniz . Gelecekte başka bir sorun çıkarsa, SQL'inize pre-processtek bir yerde hazırsınız demektir . Güncelleme yöntemini kaldırmaya gitmedim, çünkü Yönetici erişimi + kaldırsanız bile herkesin doğru sürüme ulaşması çok uzun sürecek + bazı son kullanıcıların grup politikası en son güncellemeyi tekrar yükleyecek. Aynı probleme geri döndünüz.

Kaynak koduna erişiminiz varsa use this methodve hiçbir son kullanıcının sorunu yaşamadığından% 100 eminseniz.

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

Şimdi sadece CTRL+F

Arama ve değiştirme docmd.RunSQLilehelper.Execute

Arama ve değiştirme [currentdb|dbengine|or your dbobject].executeilehelper.execute

iyi eğlenceler!


0

Tamam, burada da zil yapacağım, çünkü bu hata düzeltilmiş olsa bile, bu düzeltme henüz son kullanıcıların güncelleyemeyeceği çeşitli işletmeler aracılığıyla tam olarak doldurulmadı (işverenim gibi ...)

İşte benim geçici çözümüm DoCmd.RunSQL "UPDATE users SET uname= 'bob' WHERE usercode=1". Sorunlu sorguyu yorumlamanız ve aşağıdaki kodu girmeniz yeterlidir.

    '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

Güzel olduğunu söyleyemem, ama işi hallediyor.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.