Come ottenere l'errore 3340 Query '' è danneggiato durante l'esecuzione di query DoCmd.RunSQL


83

Dopo l'installazione l'aggiornamento di Windows per Office 2010 per risolvere KB 4.484.127 ottengo un errore durante l'esecuzione di query che contengono una clausola WHERE.

Ad esempio eseguendo questa query:

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

Risultati in questo errore:

Numero errore = 3340 La query '' è danneggiata

L' aggiornamento in questione è attualmente ancora installato:

Schermata che mostra l'aggiornamento 448127 di Microsoft Office 2010 Service Pack 2

Come posso eseguire correttamente le mie query? Devo semplicemente disinstallare questo aggiornamento?

Risposte:


92

Sommario

Questo è un bug noto causato dagli aggiornamenti di Office rilasciati il ​​12 novembre 2019. Il bug riguarda tutte le versioni di Access attualmente supportate da Microsoft (da Access 2010 a 365).

Questo errore è stato corretto.

  • Se si utilizza una versione C2R (Click-to-Run) di Office, utilizzare "Aggiorna ora" :
    • Access 2010 C2R: risolto nella build 7243.5000
    • Access 2013 C2R: risolto nella build 5197.1000
    • Accesso 2016 C2R: risolto nella build 12130.20390
    • Accesso 2019 (v1910): risolto nella build 12130.20390
    • Accesso 2019 (Volume License): risolto nella build 10353.20037
    • Canale mensile di Office 365: risolto nella build 12130.20390
    • Semestrale di Office 365: risolto nella build 11328.20480
    • Estensione semestrale di Office 365: risolto nella build 10730.20422
    • Mirato semestrale a Office 365: risolto nella build 11929.20494
  • Se si utilizza una versione MSI di Office, installare l'aggiornamento corrispondente alla versione di Office. Tutte queste patch sono state rilasciate su Microsoft Update, quindi l' installazione di tutti gli aggiornamenti di Windows in sospeso dovrebbe essere sufficiente:

Esempio

Ecco un esempio di riproduzione minima:

  1. Creare un nuovo database di Access.
  2. Creare una nuova tabella vuota "Table1" con il campo ID predefinito e un campo Intero lungo "myint".
  3. Eseguire il seguente codice nella finestra immediata dell'editor VBA:

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

Risultato previsto : l'istruzione termina correttamente.

Risultato effettivo con uno degli aggiornamenti errati installati: si verifica l'errore di run-time 3340 ("La query" è danneggiata ").


Link correlati:


9
Questo post sembra riscontrare lo stesso errore utilizzando il runtime di accesso a 64 bit e OLEDB. Cose spaventose, questo renderà molte applicazioni che usano Access per archiviare i dati inutilizzabili.
Erik A

4
Ho appena controllato un sistema con Office 2013 a 32 bit e su quel particolare computer l'UUID per l'aggiornamento è 90150000-006E-0409-0000-0000000FF1CE... -0409-non è così -0407-.
Gord Thompson,

4
Ho appena controllato un altro computer in ufficio con Office 2013 a 64 bit e anche l'UUID -006E-0409-. Entrambe le macchine hanno Service Pack 1 per Microsoft Office 2013 (KB2850036) installato.
Gord Thompson,

4
Per Office 2010 Pro Plus (SP2) dovevamo utilizzare {90140000-0011-0000-0000-0000000FF1CE}lo script batch. Nota {9014...non{9114..}
AdamsTips

2
Ho corretto l'aggiornamento ufficiale per risolvere il problema, ma sto ancora ricevendo l'errore. Qualcun altro ha avuto quel problema?
user218076

33

La soluzione più semplice

Per i miei utenti, aspettare quasi un mese fino al 10 dicembre per una versione fissa di Microsoft non è un'opzione. Né disinstallare l'aggiornamento Microsoft offensivo su diverse workstation bloccate dal governo.

Devo applicare una soluzione alternativa, ma non sono esattamente entusiasta di ciò che Microsoft ha suggerito: creare e sostituire una query per ogni tabella.

La soluzione è sostituire il nome della tabella con una semplice (SELECT * FROM Table)query direttamente nel UPDATEcomando. Ciò non richiede la creazione e il salvataggio di tonnellate di query, tabelle o funzioni aggiuntive.

ESEMPIO:

Prima:

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

Dopo:

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

Dovrebbe essere molto più facile da implementare su più database e applicazioni (e successivamente rollback).


20

Non si tratta di un problema di aggiornamento di Windows, ma di un problema introdotto con la versione di Patch Office di martedì di novembre. Una modifica per correggere una vulnerabilità della sicurezza comporta la corruzione di alcune query legittime. Poiché la modifica è stata una correzione di sicurezza, ha effetto su TUTTE le build di Office, tra cui 2010, 2013, 2016, 2019 e O365.

Il bug è stato corretto in tutti i canali, ma i tempi di consegna dipenderanno dal canale su cui ci si trova.

Per le versioni MSI 2010, 2013 e 2016 e 2019 Volume License e per il canale semestrale O365, la correzione sarà nella build martedì di dicembre, il 10 dicembre. Per O365, canale mensile e addetti ai lavori, questo sarà risolto quando verrà rilasciato il fork di ottobre, attualmente previsto per il 24 novembre.

Per il canale semestrale, il bug è stato introdotto in 11328.20468, che è stato rilasciato il 12 novembre, ma non viene distribuito a tutti contemporaneamente. Se puoi, potresti voler tenere a bada l'aggiornamento fino al 10 dicembre.

Il problema si verifica per le query di aggiornamento su una singola tabella con un criterio specificato (quindi non dovrebbero essere interessati altri tipi di query, né qualsiasi query che aggiorna tutte le righe di una tabella, né una query che aggiorna il set di risultati di un'altra query). Detto questo, la soluzione più semplice nella maggior parte dei casi consiste nel modificare la query di aggiornamento per aggiornare un'altra query che seleziona tutto dalla tabella, anziché aggiornare direttamente la query.

Cioè, se hai una domanda come:

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

Quindi, crea una nuova query (Query1) definita come:

Select * from Table1;

e aggiorna la tua query originale a:

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

Pagina ufficiale: errore di accesso: "La query è danneggiata"


13
In realtà stai dicendo con una faccia seria che andiamo a centinaia di migliaia di righe di codice distribuite su più applicazioni e sistemiamo tutti gli aggiornamenti sql che semplicemente aggiornano una riga di dati? Suppongo che se stai scrivendo una nuova query oggi e in questo momento, una soluzione del genere è possibile. Ma per il codice e le applicazioni esistenti l'idea che gli aggiornamenti sql debbano essere modificati non è ovviamente un approccio pratico alla risoluzione dei problemi in alcun modo possibile.
Albert D. Kallal,

5
@ AlbertD.Kallal, dovresti sapere dall'elenco MVP, che mi riferisco solo alla spiegazione per l'origine del problema. Come affrontare il problema dipende davvero da te e da ciò che può adattarsi al tuo scenario. Il metodo qui descritto è solo uno dei tanti.
Gustav,

1
@ AlbertD.Kallal Non è necessario rinominare le tabelle e creare QueryDefs con la vecchia correzione del nome di tabella? (Lo testerò e pubblicherò la sceneggiatura se funziona)
ComputerVersteher,

Puoi farlo senza programmazione, ad esempio rinominare la tabella "utenti" in "utenti" e quindi creare il nome della query "utenti" - e quindi funzionerà senza possibilità di programmazione ....
Zvi Redler

9
@ AlbertD.Kallal: condivido il tuo dolore - se si trattasse di un bug che interessava la libreria di runtime VC, non penso che MS ritarderebbe la correzione di un mese e suggerirebbe una soluzione alternativa "riscrivi, ricompila e ridistribuisci". (Per essere onesti, hanno risolto e rilasciato rapidamente il problema VBA a fine agosto.) Ma non spariamo al messaggero - Gustav non sembra essere un dipendente della SM. Speriamo che riconsiderino e rilascino una patch in precedenza; dopo tutto, influisce anche sulle applicazioni scritte in altre lingue che utilizzano il motore Access DB .
Heinzi,

15

Per risolvere temporaneamente questo problema dipende dalla versione di Access in uso:
Access 2010 Disinstalla aggiornamento KB4484127
Access 2013 Disinstalla aggiornamento KB4484119
Access 2016 Disinstalla aggiornamento KB4484113
Access 2019 SE RICHIESTO (da confermare). Downgrade dalla versione 1808 (build 10352.20042) alla versione 1808 (build 10351.20054)
Office 365 ProPlus Downgrade dalla versione 1910 (build 12130.20344) a una build precedente, vedere https://support.microsoft.com/en-gb/help/2770432/ how-to-revert-to-an-precedenti-version-of-office-2013-o-office-2016-clic


L'ho disinstallato, ma è stato reinstallato al successivo avvio di Windows. Come si impedisce la reinstallazione?
dsteele il

5
@dsteele Se versione MSI e nessun WSUS, utilizzare support.microsoft.com/en-us/help/3073930/… strumento di risoluzione dei problemi. Il CTR disabilita gli aggiornamenti in Impostazioni account di Office.
ComputerVersteher

5

Noi e i nostri clienti abbiamo lottato con questo negli ultimi due giorni e finalmente abbiamo scritto un documento per discutere in dettaglio il problema insieme ad alcune soluzioni: http://fmsinc.com/MicrosoftAccess/Errors/query_is_corrupt/

Include le nostre scoperte che incidono sulle soluzioni di Access durante l'esecuzione di query di aggiornamento su tabelle locali, tabelle di Access collegate e persino tabelle di SQL Server collegate.

Incide anche su soluzioni non Microsoft Access che utilizzano Access Database Engine (ACE) per connettersi a database Access utilizzando ADO. Ciò include le app di Visual Studio (WinForm), le app VB6 e persino i siti Web che aggiornano i database di Access su macchine su cui non è mai stato installato Access o Office.

Questo arresto può persino influire sulle app Microsoft che utilizzano ACE come PowerBI, Power Query, SSMA, ecc. (Non confermato) e, naturalmente, altri programmi come Excel, PowerPoint o Word che utilizzano VBA per modificare i database di Access.

Oltre all'ovvia disinstallazione degli aggiornamenti della sicurezza offensivi, includiamo anche alcune opzioni quando non è possibile disinstallare a causa di autorizzazioni o distribuzione di applicazioni di accesso a clienti esterni i cui PC sono fuori dal tuo controllo. Ciò include la modifica di tutte le query di aggiornamento e la distribuzione delle applicazioni di Access utilizzando Access 2007 (vendita al dettaglio o runtime) poiché tale versione non è influenzata dagli aggiornamenti di sicurezza.


4

Utilizzare il modulo seguente per implementare automaticamente la soluzione alternativa suggerita da Microsoft (utilizzando una query anziché una tabella). Per precauzione, eseguire prima il backup del database.

Utilizzare AddWorkaroundForCorruptedQueryIssue()per aggiungere la soluzione alternativa e RemoveWorkaroundForCorruptedQueryIssue()per rimuoverla in qualsiasi momento.

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

Puoi trovare l'ultimo codice sul mio repository GitHub .

AddWorkaroundForCorruptedQueryIssue()aggiungerà il suffisso _Tablea tutte le tabelle non di sistema, ad esempio la tabella IceCreamsverrà rinominata IceCreams_Table.

Creerà anche una nuova query utilizzando il nome della tabella originale, che selezionerà tutte le colonne della tabella rinominata. Nel nostro esempio, la query verrà denominata IceCreamsed eseguirà l'SQL select * from [IceCreams_Table].

RemoveWorkaroundForCorruptedQueryIssue() fa le azioni inverse.

Ho provato questo con tutti i tipi di tabelle, comprese le tabelle esterne non MDB (come SQL Server). Tuttavia, tenere presente che l'utilizzo di una query anziché di una tabella può comportare l'esecuzione di query non ottimizzate su un database back-end in casi specifici, soprattutto se le query originali che hanno utilizzato le tabelle sono di scarsa qualità o molto complesse.

(E ovviamente, a seconda del tuo stile di codifica, è anche possibile rompere le cose nella tua applicazione. Quindi, dopo aver verificato che la correzione in genere funziona per te, non è mai una cattiva idea esportare tutti i tuoi oggetti come testo e usare alcuni sostituisci magia per garantire che tutte le occorrenze dei nomi delle tabelle vengano eseguite sulle query e non sulle tabelle.)

Nel mio caso, questa correzione funziona in gran parte senza effetti collaterali, ho solo bisogno di rinominare manualmente USysRibbons_Tabledi nuovo a USysRibbons, come non avevo segnato come una tabella di sistema quando ho creato in passato.


Mi piace che tu determini un instabile con TableDef.Attributese lo copi nella mia risposta;) e una funzione di annullamento è una buona idea (ma il vecchio e il nuovo nome dovrebbero essere archiviati in una tabella in quanto non dipendono da tabelle con suffisso prima della ridenominazione). Alcune altre parti sono difettose (ad es. Le tabelle possono terminare con il suffisso o il nuovo nome è già in uso o On Error Resume Nextsenza errori di gestione in seguito). Conosci RubberduckVBA ? Questo componente aggiuntivo è in grado di ispezionare il tuo codice e fornisce suggerimenti utili per migliorare, oltre a tutte le altre funzionalità.
ComputerVersteher

E dovresti indicare i bug che il nostro approccio può causare (vedi i commenti di @Erics sulla mia risposta)
ComputerVersteher

Ah, non ho visto che c'era già una risposta simile qui, quindi grazie per la recensione! Il suffisso è definito nella sua costante, quindi può essere facilmente modificato nel caso in cui sia già stato definito un oggetto preesistente che utilizza già il suffisso. Altrimenti la sceneggiatura funziona così com'è ma chiunque dovrebbe sentirsi incoraggiato a modificarla in base alle proprie esigenze individuali. Lo script è stato testato su progetti abbastanza grandi (oltre 400 tabelle) incluse tabelle esterne / collegate a diverse origini di database esterne. Non sapevo di Rubberduck (solo su MZ-Tools). Li controllerò sicuramente!
lauxjpn,

3

Per coloro che desiderano automatizzare questo processo tramite PowerShell , ecco alcuni link che ho trovato utili:

Rileva e rimuovi gli aggiornamenti offensivi

C'è uno script di PowerShell disponibile qui https://www.arcath.net/2017/09/office-update-remover che cerca nel registro uno specifico aggiornamento di Office (passato come numero kb) e lo rimuove usando una chiamata a msiexec.exe. Questo script analizza entrambi i GUID dalle chiavi del Registro di sistema per creare il comando per rimuovere l'aggiornamento appropriato.

Una modifica che suggerirei sarebbe quella di utilizzare /REBOOT=REALLYSUPPRESScome descritto in Come disinstallare KB4011626 e altri aggiornamenti di Office (Riferimento aggiuntivo: https://docs.microsoft.com/en-us/windows/win32/msi/uninstalling-patches ). La riga di comando che stai creando è simile a questa:

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

Il comando per eseguire lo script sarebbe simile al seguente:

OfficeUpdateRemover.ps1 -kb 4484127

Impedisci l'installazione degli aggiornamenti

L'approccio consigliato qui sembra nascondere l'aggiornamento . Ovviamente questo può essere fatto manualmente, ma ci sono alcuni script PowerShell che possono aiutare con l'automazione. Questo link: https://www.maketecheasier.com/hide-updates-in-windows-10/ descrive il processo in dettaglio, ma lo riassumerò qui.

  1. Installa il modulo PowerShell di Windows Update .
  2. Utilizzare il comando seguente per nascondere un aggiornamento per numero KB:

    Hide-WUUpdate -KBArticleID KB4484127

Spero che questo possa essere d'aiuto a qualcun altro là fuori.


3

VBA-Script per soluzione alternativa MS:

Si consiglia di rimuovere l'aggiornamento con errori, se possibile (se non provare il mio codice), almeno per le versioni MSI. Vedi risposta https://stackoverflow.com/a/58833831/9439330 .

Per le versioni CTR (click-to-run), è necessario rimuovere tutti gli aggiornamenti di Office di novembre, ciò che potrebbe causare seri problemi di sicurezza (non sono sicuro se eventuali correzioni critiche verranno rimosse).

Dai commenti di @ Eric:

  • Se si utilizza Table.Tablenameper associare i moduli, questi non vengono associati poiché il nome della tabella precedente ora è un nome di query !.
  • OpenRecordSet(FormerTableNowAQuery, dbOpenTable) fallirà (dato che ora è una query, non più una tabella)

Attenzione! Appena testato rapidamente contro Northwind.accdb su Office 2013 x86 CTR Nessuna garanzia!

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

Per i test:

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
Si noti che questa soluzione alternativa rovinerà le sottomaschere associate alle tabelle (sarà necessario rimbalzare alle query) e il codice funzionerà con tabledefs con un nome di tabella codificato. Usare con grande cautela, le probabilità sono che questo risolva un bug solo per crearne due nuovi a seconda di ciò che l'applicazione sta facendo.
Erik A

@ErikA Ovviamente solo una soluzione alternativa, ma posso legare Inventory to reorder Subform for Homealla Inventorytabella nella Homeforma, senza problemi. Non è nemmeno raccomandato di associare i moduli alle query anziché alle tabelle (non è vincolante per le tabelle come Select * From table?).
ComputerVersteher

2
Se associo una sottomaschera a una tabella, generalmente lo faccio usando la Table.TableNamenotazione. Se lo fai SELECT * FROM TableNameinvece, ovviamente stai bene. Ma se si utilizza Table.TableName, la sottomaschera non verrà associata se si rinomina la tabella.
Erik A

@ErikA: È vero. Qualche vantaggio nel farlo?
ComputerVersteher,

3
Non per quanto ne so, tranne per il fatto che è più breve. Vi è tuttavia un sostanziale vantaggio TableDefs!MyTableName.OpenRecordset(dbOpenTable)(supporto per la ricerca di indici), che anch'io tendo a utilizzare e causerà anche errori nel tuo approccio
Erik A

2

Ho sostituito currentDb.Executee Docmd.RunSQLcon una funzione di aiuto. Ciò può pre-elaborare e modificare l'istruzione SQL se un'istruzione di aggiornamento contiene solo una tabella. Ho già una dualtabella (a riga singola, a colonna singola) quindi ho scelto l'opzione fakeTable.

Nota : questo non cambierà gli oggetti query. Aiuterà solo esecuzioni SQL tramite 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.

Questo è solo un concetto (If it's a single table update modify the sql before execution). Adattalo secondo le tue esigenze. Questo metodo non crea query di sostituzione per ogni tabella (che può essere il modo più semplice ma ha i suoi svantaggi. Cioè problemi di prestazioni)

+ Punti: puoi continuare a usare questo aiutante anche dopo che MS ha corretto il bug che non cambierà nulla. Nel caso, il futuro porti un altro problema, sei pronto per il pre-processtuo SQL in un unico posto. Non ho optato per la disinstallazione del metodo degli aggiornamenti perché ciò richiede l'accesso come amministratore + richiederà troppo tempo per ottenere tutti sulla versione corretta + anche se si disinstalla, alcuni criteri di gruppo degli utenti finali installano di nuovo l'ultimo aggiornamento. Sei tornato allo stesso problema.

Se hai accesso al codice sorgente use this methode sei sicuro al 100% che nessun utente finale sta riscontrando il problema.

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

Ora solo CTRL+F

Cerca e sostituisci docmd.RunSQLconhelper.Execute

Cerca e sostituisci [currentdb|dbengine|or your dbobject].executeconhelper.execute

divertiti!


0

Ok anche qui, perché anche se questo bug è stato corretto, quella correzione deve ancora essere popolata completamente attraverso varie aziende in cui gli utenti finali potrebbero non essere in grado di aggiornare (come il mio datore di lavoro ...)

Ecco la mia soluzione alternativa per DoCmd.RunSQL "UPDATE users SET uname= 'bob' WHERE usercode=1". Basta commentare la query offensiva e rilasciare il codice qui sotto.

    '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

Non posso dire che sia carino, ma ottiene il lavoro fatto.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.