Abrufen des Fehlers 3340 Die Abfrage '' ist beim Ausführen der Abfragen DoCmd.RunSQL beschädigt


83

Seit der Installation des Windows-Updates für Office 2010 zum Auflösen von KB 4484127 wird beim Ausführen von Abfragen, die eine WHERE-Klausel enthalten, eine Fehlermeldung angezeigt .

Beispiel: Ausführen dieser Abfrage:

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

Ergebnisse in diesem Fehler:

Fehlernummer = 3340 Abfrage '' ist beschädigt

Das betreffende Update ist derzeit noch installiert:

Screenshot mit dem Microsoft Office 2010 Service Pack 2-Update 448127

Wie kann ich meine Abfragen erfolgreich ausführen? Sollte ich dieses Update einfach deinstallieren?

Antworten:


92

Zusammenfassung

Dies ist ein bekannter Fehler , der durch die am 12. November 2019 veröffentlichten Office-Updates verursacht wurde. Der Fehler betrifft alle Versionen von Access, die derzeit von Microsoft unterstützt werden (von Access 2010 bis 365).

Dieser Fehler wurde behoben.

  • Wenn Sie eine C2R-Version (Click-to-Run) von Office verwenden, verwenden Sie "Jetzt aktualisieren " :
    • Access 2010 C2R: In Build 7243.5000 behoben
    • Access 2013 C2R: In Build 5197.1000 behoben
    • Access 2016 C2R: In Build 12130.20390 behoben
    • Zugriff 2019 (v1910): In Build 12130.20390 behoben
    • Zugriff 2019 (Volumenlizenz): In Build 10353.20037 behoben
    • Office 365-Monatskanal: In Build 12130.20390 behoben
    • Office 365 halbjährlich: In Build 11328.20480 behoben
    • Office 365 Semi-Annual Extended: In Build 10730.20422 behoben
    • Office 365 Semi-Annual Targeted: In Build 11929.20494 behoben
  • Wenn Sie eine MSI-Version von Office verwenden, installieren Sie das Update, das Ihrer Office-Version entspricht. Alle diese Patches wurden in Microsoft Update veröffentlicht. Daher sollte die Installation aller ausstehenden Windows-Updates ausreichen:

Beispiel

Hier ist ein minimales Repro-Beispiel:

  1. Erstellen Sie eine neue Access-Datenbank.
  2. Erstellen Sie eine neue, leere Tabelle "Table1" mit dem Standard-ID-Feld und einem Long Integer-Feld "myint".
  3. Führen Sie den folgenden Code im Direktfenster des VBA-Editors aus:

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

Erwartetes Ergebnis : Die Anweisung wird erfolgreich beendet.

Tatsächliches Ergebnis mit einem der installierten fehlerhaften Updates: Laufzeitfehler 3340 tritt auf ("Abfrage '' ist beschädigt").


Verwandte Links:


9
Dieser Beitrag scheint denselben Fehler bei der Verwendung der 64-Bit-Zugriffslaufzeit und der OLEDB zu haben. Dies macht viele Anwendungen, die Access zum Speichern von Daten verwenden, unbrauchbar.
Erik A

4
Ich habe gerade ein System mit Office 2013 32-Bit überprüft und auf diesem bestimmten Computer lautet die UUID für das Update 90150000-006E-0409-0000-0000000FF1CE... das -0409-ist nicht der Fall -0407-.
Gord Thompson

4
Ich habe gerade einen anderen Computer im Büro überprüft, der über Office 2013 64-Bit verfügt, und die UUID ist -006E-0409-ebenfalls vorhanden. Auf beiden Computern ist Service Pack 1 für Microsoft Office 2013 (KB2850036) installiert.
Gord Thompson

4
Für Office 2010 Pro Plus (SP2) mussten wir {90140000-0011-0000-0000-0000000FF1CE}das Batch-Skript verwenden. {9014...Nicht beachten{9114..}
AdamsTips

2
Ich habe mit dem offiziellen Update gepatcht, um das Problem zu beheben, aber ich erhalte immer noch den Fehler. Hat noch jemand dieses Problem?
user218076

33

Einfachste Lösung

Für meine Benutzer ist es keine Option, fast einen Monat bis zum 10. Dezember auf eine feste Version von Microsoft zu warten. Die Deinstallation des fehlerhaften Microsoft-Updates auf mehreren von der Regierung gesperrten Workstations ist ebenfalls nicht möglich.

Ich muss eine Problemumgehung anwenden, bin aber nicht gerade begeistert von den Vorschlägen von Microsoft - dem Erstellen und Ersetzen einer Abfrage für jede Tabelle.

Die Lösung besteht darin, den Tabellennamen durch einen einfachen zu ersetzen (SELECT * FROM Table) Abfrage direkt im UPDATEBefehl . Dies erfordert nicht das Erstellen und Speichern einer Menge zusätzlicher Abfragen, Tabellen oder Funktionen.

BEISPIEL:

Vor:

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

Nach:

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

Dies sollte in mehreren Datenbanken und Anwendungen (und späterem Rollback) viel einfacher zu implementieren sein.


20

Dies ist kein Windows-Update-Problem, sondern ein Problem, das mit der Veröffentlichung des November Patch Tuesday Office eingeführt wurde. Eine Änderung zur Behebung einer Sicherheitslücke führt dazu, dass einige legitime Abfragen als beschädigt gemeldet werden. Da es sich bei der Änderung um eine Sicherheitskorrektur handelt, wirkt sie sich auf ALLE Office-Builds aus, einschließlich 2010, 2013, 2016, 2019 und O365.

Der Fehler wurde in allen Kanälen behoben, aber der Zeitpunkt der Lieferung hängt davon ab, auf welchem ​​Kanal Sie sich befinden.

Für die MSI- und 2019-Volumenlizenz-Builds 2010, 2013 und 2016 sowie den halbjährlichen O365-Kanal wird der Fix im Dezember-Patch-Dienstag-Build vom 10. Dezember enthalten sein. Für O365, Monthly Channel und Insider wird dies behoben Wenn die Oktobergabel freigegeben wird, ist dies derzeit für den 24. November geplant.

Für den halbjährlichen Kanal wurde der Fehler in 11328.20468 eingeführt, der am 12. November veröffentlicht wurde, aber nicht für alle auf einmal verfügbar ist. Wenn Sie können, möchten Sie die Aktualisierung möglicherweise bis zum 10. Dezember verschieben.

Das Problem tritt bei Aktualisierungsabfragen für eine einzelne Tabelle mit festgelegten Kriterien auf (daher sollten andere Abfragetypen nicht betroffen sein, keine Abfrage, die alle Zeilen einer Tabelle aktualisiert, oder eine Abfrage, die die Ergebnismenge einer anderen Abfrage aktualisiert). Angesichts dessen besteht die einfachste Problemumgehung in den meisten Fällen darin, die Aktualisierungsabfrage so zu ändern, dass eine andere Abfrage aktualisiert wird, die alles aus der Tabelle auswählt, anstatt die Abfrage direkt zu aktualisieren.

Dh wenn Sie eine Frage haben wie:

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

Erstellen Sie dann eine neue Abfrage (Query1), die wie folgt definiert ist:

Select * from Table1;

und aktualisieren Sie Ihre ursprüngliche Abfrage auf:

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

Offizielle Seite: Zugriffsfehler: "Abfrage ist beschädigt"


13
Wollen Sie tatsächlich mit ernstem Gesicht sagen, dass wir zu Hunderttausenden von Codezeilen gehen, die in mehreren Anwendungen bereitgestellt werden, und alle SQL-Updates korrigieren, die einfach eine Datenzeile aktualisieren? Ich nehme an, wenn Sie heute und jetzt eine neue Abfrage schreiben, ist eine solche Problemumgehung möglich. Aber für vorhandenen Code und Anwendungen ist die Idee, dass SQL-Updates geändert werden sollen, natürlich kein praktischer Ansatz, um Probleme auf irgendeine mögliche Weise zu lösen.
Albert D. Kallal

5
@ AlbertD.Kallal, Sie sollten aus der MVP-Liste wissen, dass ich mich nur auf die Erklärung für die Quelle des Problems beziehe. Wie Sie mit dem Problem umgehen, liegt ganz bei Ihnen und was zu Ihrem Szenario passt. Die hier beschriebene Methode ist nur eine von mehreren.
Gustav

1
@ AlbertD.Kallal Sollte das nicht behoben werden, indem Tabellen nicht umbenannt und QueryDefs mit altem Tabellennamen erstellt wurden? (Ich werde das testen und das Skript veröffentlichen, wenn es funktioniert)
ComputerVersteher

Sie können dies ohne Programmierung tun, z. B. die Tabelle "Benutzer" in "Benutzer" umbenennen und dann den Abfragenamen "Benutzer" erstellen - und dann funktioniert es ohne Programmierkanal ....
Zvi Redler

9
@ AlbertD.Kallal: Ich teile Ihren Schmerz - wenn dies ein Fehler wäre, der die VC-Laufzeitbibliothek betrifft, würde MS den Fix meiner Meinung nach nicht um einen Monat verzögern und eine Problemumgehung zum Umschreiben, Neukompilieren und erneuten Bereitstellen vorschlagen. (Um fair zu sein, haben sie das VBA-Problem Ende August schnell behoben und veröffentlicht.) Aber lasst uns nicht auf den Messenger schießen - Gustav scheint kein MS-Mitarbeiter zu sein. Hoffen wir, dass sie einen Patch früher überdenken und veröffentlichen. Schließlich sind auch Anwendungen betroffen , die in anderen Sprachen geschrieben wurden und zufällig die Access DB-Engine verwenden .
Heinzi

15

Die vorübergehende Behebung dieses Problems hängt von der verwendeten Access-Version ab:
Access 2010-Deinstallationsupdate KB4484127
Access 2013-Deinstallationsupdate KB4484119
Access 2016-Deinstallationsupdate KB4484113
Access 2019, WENN ERFORDERLICH (tbc). Downgrade von Version 1808 (Build 10352.20042) auf Version 1808 (Build 10351.20054)
Office 365 ProPlus-Downgrade von Version 1910 (Build 12130.20344) auf einen früheren Build, siehe https://support.microsoft.com/en-gb/help/2770432/ Wie man zu einer früheren Version von Office 2013 oder Office 2016 zurückkehrt


Ich habe es deinstalliert, aber es wurde beim nächsten Start von Windows neu installiert. Wie verhindern Sie eine Neuinstallation?
Dsteele

5
@dsteele Wenn die MSI-Version und kein WSUS vorhanden sind, verwenden Sie das Tool zur Fehlerbehebung unter support.microsoft.com/en-us/help/3073930/… . Auf CTR deaktivieren Sie Updates in Office-Account-Einstellungen ..
ComputerVersteher

5

Wir und unsere Kunden haben in den letzten zwei Tagen damit zu kämpfen und schließlich ein Papier geschrieben, um das Problem zusammen mit einigen Lösungen ausführlich zu erörtern: http://fmsinc.com/MicrosoftAccess/Errors/query_is_corrupt/

Es enthält unsere Erkenntnisse, dass es sich auf Access-Lösungen auswirkt, wenn Aktualisierungsabfragen für lokale Tabellen, verknüpfte Access-Tabellen und sogar verknüpfte SQL Server-Tabellen ausgeführt werden.

Dies wirkt sich auch auf Nicht-Microsoft Access-Lösungen aus, die das Access Database Engine (ACE) verwenden, um mithilfe von ADO eine Verbindung zu Access-Datenbanken herzustellen. Dazu gehören Visual Studio (WinForm) -Apps, VB6-Apps und sogar Websites, auf denen Access-Datenbanken auf Computern aktualisiert werden, auf denen Access oder Office noch nie installiert waren.

Dieser Absturz kann sich sogar auf Microsoft-Apps auswirken, die ACE verwenden, z. B. PowerBI, Power Query, SSMA usw. (nicht bestätigt), und natürlich auf andere Programme wie Excel, PowerPoint oder Word, die VBA zum Ändern von Access-Datenbanken verwenden.

Zusätzlich zur offensichtlichen Deinstallation der fehlerhaften Sicherheitsupdates bieten wir einige Optionen an, wenn eine Deinstallation aufgrund von Berechtigungen oder der Verteilung von Access-Anwendungen an externe Kunden, deren PCs außerhalb Ihrer Kontrolle liegen, nicht möglich ist. Dazu gehört das Ändern aller Update-Abfragen und das Verteilen der Access-Anwendungen mit Access 2007 (Einzelhandel oder Laufzeit), da diese Version von den Sicherheitsupdates nicht betroffen ist.


4

Verwenden Sie das folgende Modul, um die von Microsoft vorgeschlagene Problemumgehung automatisch zu implementieren (mithilfe einer Abfrage anstelle einer Tabelle). Sichern Sie vorsichtshalber zuerst Ihre Datenbank.

Verwenden AddWorkaroundForCorruptedQueryIssue()Sie diese Option, um die Problemumgehung hinzuzufügen und RemoveWorkaroundForCorruptedQueryIssue()jederzeit zu entfernen.

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

Sie finden den neuesten Code in meinem GitHub-Repository .

AddWorkaroundForCorruptedQueryIssue()fügt das Suffix _Tableallen Nicht-Systemtabellen hinzu, z. B. würde die Tabelle IceCreamsin umbenannt IceCreams_Table.

Außerdem wird eine neue Abfrage unter Verwendung des ursprünglichen Tabellennamens erstellt, die alle Spalten der umbenannten Tabelle auswählt. In unserem Beispiel würde die Abfrage benannt IceCreamsund die SQL ausführen select * from [IceCreams_Table].

RemoveWorkaroundForCorruptedQueryIssue() macht die umgekehrten Aktionen.

Ich habe dies mit allen Arten von Tabellen getestet, einschließlich externer Nicht-MDB-Tabellen (wie SQL Server). Beachten Sie jedoch, dass die Verwendung einer Abfrage anstelle einer Tabelle in bestimmten Fällen dazu führen kann, dass nicht optimierte Abfragen für eine Backend-Datenbank ausgeführt werden, insbesondere wenn Ihre ursprünglichen Abfragen, die die Tabellen verwendet haben, entweder von schlechter Qualität oder sehr komplex sind.

(Und natürlich ist es abhängig von Ihrem Codierungsstil auch möglich, Dinge in Ihrer Anwendung zu beschädigen. Nachdem Sie überprüft haben, dass das Update im Allgemeinen für Sie funktioniert, ist es nie eine schlechte Idee, alle Ihre Objekte als Text zu exportieren und einen Suchersatz zu verwenden Magie, um sicherzustellen, dass alle Vorkommen von Tabellennamen für die Abfragen und nicht für die Tabellen ausgeführt werden.)

In meinem Fall funktioniert dieses Update weitgehend ohne Nebenwirkungen, ich nur manuell benötigt umbenennen USysRibbons_Tablewieder zu USysRibbons, wie ich es als Systemtabelle nicht markiert war , als ich es in der Vergangenheit erstellt.


Ich mag es, wenn Sie eine Systemtabelle bestimmen TableDef.Attributesund diese in meine Antwort kopieren;) und eine Rückgängig-Funktion ist eine gute Idee (aber alte und neue Namen sollten in einer Tabelle gespeichert werden, da keine Tabellen mit Suffix vor dem Umbenennen vorhanden sind). Einige andere Teile sind fehlerhaft (z. B. können Tabellen mit dem Suffix enden oder der neue Name wird bereits verwendet oder später werden On Error Resume Nextkeine Fehler behandelt). Kennen Sie RubberduckVBA ? Dieses Add-In kann Ihren Code überprüfen und macht neben allen anderen Funktionen nette Vorschläge für Verbesserungen.
ComputerVersteher

Und Sie sollten auf die Fehler hinweisen, die unser Ansatz verursachen kann (siehe @Erics Kommentare zu meiner Antwort)
ComputerVersteher

Ah, ich habe nicht gesehen, dass es hier bereits eine ähnliche Antwort gibt, also danke für die Bewertung! Das Suffix wird in einer eigenen Konstante definiert, sodass es leicht geändert werden kann, falls ein bereits vorhandenes Objekt definiert ist, das das Suffix bereits verwendet. Ansonsten funktioniert das Skript wie es ist, aber jeder sollte sich ermutigt fühlen, es an seine individuellen Bedürfnisse anzupassen. Das Skript wurde in relativ großen Projekten (über 400 Tabellen) getestet, einschließlich externer / verknüpfter Tabellen mit verschiedenen externen Datenbankquellen. Ich wusste nichts über Rubberduck (nur über MZ-Tools). Ich werde sie auf jeden Fall ausprobieren!
Lauxjpn

3

Für diejenigen, die diesen Prozess über PowerShell automatisieren möchten , sind hier einige Links aufgeführt, die hilfreich sein können:

Erkennen und Entfernen der fehlerhaften Updates

Hier ist ein PowerShell-Skript verfügbar: https://www.arcath.net/2017/09/office-update-remover , das die Registrierung nach einem bestimmten Office-Update durchsucht (als KB-Nummer übergeben) und es mithilfe eines Aufrufs an entfernt msiexec.exe. Dieses Skript analysiert beide GUIDs aus den Registrierungsschlüsseln, um den Befehl zum Entfernen des entsprechenden Updates zu erstellen.

Eine Änderung, die ich vorschlagen würde, wäre die Verwendung der /REBOOT=REALLYSUPPRESSunter So deinstallieren von KB4011626 und anderen Office-Updates beschriebenen (zusätzliche Referenz: https://docs.microsoft.com/en-us/windows/win32/msi/uninstalling-patches ). Die Befehlszeile, die Sie erstellen, sieht folgendermaßen aus:

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

Der Befehl zum Ausführen des Skripts würde ungefähr so ​​aussehen:

OfficeUpdateRemover.ps1 -kb 4484127

Verhindern Sie die Installation der Updates

Der hier empfohlene Ansatz scheint das Update zu verbergen . Natürlich kann dies manuell erfolgen, aber es gibt einige PowerShell-Skripte, die bei der Automatisierung helfen können. Dieser Link: https://www.maketecheasier.com/hide-updates-in-windows-10/ beschreibt den Prozess im Detail, aber ich werde ihn hier zusammenfassen.

  1. Installieren Sie das Windows Update PowerShell-Modul .
  2. Verwenden Sie den folgenden Befehl, um ein Update nach KB-Nummer auszublenden:

    Hide-WUUpdate -KBArticleID KB4484127

Hoffentlich hilft dies jemand anderem da draußen.


3

VBA-Skript für MS-Workaround:

Es wird empfohlen, das fehlerhafte Update nach Möglichkeit zu entfernen (wenn nicht, versuchen Sie es mit meinem Code), zumindest für die MSI-Versionen. Siehe Antwort https://stackoverflow.com/a/58833831/9439330 .

Bei CTR-Versionen (Click-To-Run) müssen Sie alle Office November-Updates entfernen, was zu schwerwiegenden Sicherheitsproblemen führen kann (nicht sicher, ob kritische Korrekturen entfernt werden).

Aus @ Erics Kommentaren:

  • Wenn Sie Table.TablenameFormulare zum Binden verwenden, werden sie nicht mehr gebunden, da der frühere Tabellenname jetzt ein Abfragename ist.
  • OpenRecordSet(FormerTableNowAQuery, dbOpenTable) wird fehlschlagen (da es jetzt eine Abfrage ist, keine Tabelle mehr)

Vorsicht! Nur schnell gegen Northwind.accdb auf Office 2013 x86 CTR getestet Keine Garantie!

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

Zum Prüfen:

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
Beachten Sie, dass diese Problemumgehung Unterformulare ruiniert, die an Tabellen gebunden sind (müssen an Abfragen zurückgebunden werden) und Code, der mit Tabledefs mit einem fest codierten Tabellennamen arbeitet. Verwenden Sie dies mit großer Vorsicht. Es besteht die Möglichkeit, dass nur ein Fehler behoben wird, um zwei neue Fehler zu erstellen, je nachdem, was Ihre Anwendung tut.
Erik A

@ErikA Natürlich nur eine Problemumgehung, aber ich kann bindenInventory to reorder Subform for Home ohne Probleme Inventoryin HomeForm an eine Tabelle . Auch ist es nicht empfehlenswert, Formulare an Abfragen anstatt an Tabellen zu binden (ist das nicht an Tabellen gebunden wie Select * From table?).
ComputerVersteher

2
Wenn ich ein Unterformular an eine Tabelle binde, mache ich das normalerweise mit der Table.TableNameNotation. Wenn Sie tunSELECT * FROM TableName stattdessen , geht es Ihnen natürlich gut. Wenn Sie jedoch verwenden Table.TableName, wird Ihr Unterformular ungebunden, wenn Sie die Tabelle umbenennen.
Erik A

@ErikA: Das stimmt. Nutzen Sie das?
ComputerVersteher

3
Nicht so weit ich weiß, außer dass es kürzer ist. Es gibt jedoch einen wesentlichen Vorteil TableDefs!MyTableName.OpenRecordset(dbOpenTable)(Unterstützung der Indexsuche), den ich auch tendenziell benutze und der auch Fehler bei Ihrem Ansatz verursachen wird
Erik A

2

Ich habe das currentDb.Executeund Docmd.RunSQLdurch eine Hilfsfunktion ersetzt. Dadurch kann die SQL-Anweisung vorverarbeitet und geändert werden, wenn eine Aktualisierungsanweisung nur eine Tabelle enthält. Ich habe bereits eine dualTabelle (einzeilig, einspaltig), also habe ich mich für eine fakeTable-Option entschieden.

Hinweis : Dadurch werden Ihre Abfrageobjekte nicht geändert. Es werden nur SQL-Ausführungen über VBA unterstützt.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.

Dies ist nur ein Konzept (If it's a single table update modify the sql before execution). Passen Sie es Ihren Bedürfnissen an. Diese Methode erstellt keine Ersatzabfragen für jede Tabelle (was der einfachste Weg ist, aber seine eigenen Nachteile hat, dh Leistungsprobleme).

+ Punkte: Sie können diesen Helfer auch dann weiter verwenden, wenn MS den Fehler behoben hat. Er ändert nichts. Falls die Zukunft ein anderes Problem mit sich bringt, sind pre-processSie an einem Ort bereit für Ihre SQL. Ich habe mich nicht für die Deinstallation der Update- Methode entschieden, da hierfür der Administratorzugriff erforderlich ist. + Es wird zu lange dauern, bis alle Benutzer die richtige Version erhalten. + Selbst wenn Sie deinstallieren, installiert die Gruppenrichtlinie einiger Endbenutzer das neueste Update erneut. Sie sind wieder beim gleichen Problem.

Wenn Sie Zugriff auf den Quellcode haben use this methodund zu 100% sicher sind, dass kein Endbenutzer das Problem hat.

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

Jetzt nur noch CTRL+F

Suchen und ersetzen docmd.RunSQLdurchhelper.Execute

Suchen und ersetzen [currentdb|dbengine|or your dbobject].executedurchhelper.execute

habe Spaß!


0

Ok, ich melde mich auch hier, denn obwohl dieser Fehler behoben wurde, muss dieser Fix noch vollständig in verschiedenen Unternehmen ausgefüllt werden, in denen die Endbenutzer möglicherweise keine Updates durchführen können (wie bei meinem Arbeitgeber ...).

Hier ist meine Problemumgehung für DoCmd.RunSQL "UPDATE users SET uname= 'bob' WHERE usercode=1". Kommentieren Sie einfach die beleidigende Abfrage aus und geben Sie den folgenden Code ein.

    '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

Ich kann nicht sagen, dass es hübsch ist, aber es erledigt den Job.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.