Получение ошибки 3340 Запрос '' поврежден при выполнении запросов DoCmd.RunSQL

83

После установки обновления Windows для Office 2010 с разрешением в 4484127 КБ я получаю сообщение об ошибке при выполнении запросов, содержащих предложение WHERE.

Например, выполняя этот запрос:

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

Результаты в этой ошибке:

Номер ошибки = 3340 Запрос '' поврежден

Данное обновление в настоящее время все еще установлено:

Снимок экрана: обновление пакета обновления 2 для Microsoft Office 2010 448127

Как я могу успешно выполнить мои запросы? Должен ли я просто удалить это обновление?

Цви Редлер
источник

Ответы:

92

Резюме

Это известная ошибка, вызванная обновлениями Office, выпущенными 12 ноября 2019 года. Эта ошибка затрагивает все версии Microsoft Access, поддерживаемые в настоящее время (от Access 2010 до 365).

Эта ошибка была исправлена.

  • Если вы используете C2R (Click-to-Run) версию Office, используйте «Обновить сейчас» :
    • Access 2010 C2R: исправлено в сборке 7243.5000
    • Access 2013 C2R: исправлено в сборке 5197.1000
    • Access 2016 C2R: исправлено в сборке 12130.20390
    • Access 2019 (v1910): исправлено в сборке 12130.20390
    • Access 2019 (корпоративная лицензия): исправлено в сборке 10353.20037
    • Ежемесячный канал Office 365: исправлено в сборке 12130.20390
    • Office 365 полугодовой: исправлено в сборке 11328.20480
    • Office 365, полугодовой расширенный: исправлено в сборке 10730.20422
    • Office 365, ориентированный на полугодовой период: исправлено в сборке 11929.20494
  • Если вы используете MSI-версию Office, установите обновление, соответствующее вашей версии Office. Все эти исправления были выпущены в Центре обновления Microsoft, поэтому достаточно установить все ожидающие обновления Windows :
    • MSI Access 2010: исправлено в KB4484193
    • MSI Access 2013: исправлено в KB4484186
    • Access 2016 MSI: исправлено в KB4484180

пример

Вот минимальный пример воспроизведения:

  1. Создайте новую базу данных Access.
  2. Создайте новую пустую таблицу «Table1» с полем идентификатора по умолчанию и длинным целым полем «myint».
  3. Выполните следующий код в Immediate Window редактора VBA:

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

Ожидаемый результат : оператор успешно завершается.

Фактический результат с одним из установленных ошибок: Произошла ошибка 3340 во время выполнения («Запрос» поврежден).


Ссылки по теме:

Heinzi
источник
9
В этом посте, похоже, встречается та же ошибка при использовании 64-битной среды выполнения Access и OLEDB. Страшные вещи, это сделает многие приложения, которые используют Access для хранения данных, непригодными для использования.
Эрик А
4
Я только что проверил систему с Office 2013 32-битной и на этой конкретной машине UUID для обновления 90150000-006E-0409-0000-0000000FF1CE... это -0409-не так -0407-.
Горд Томпсон
4
Я только что проверил другую машину в офисе, которая имеет Office 2013 64-битный и UUID -006E-0409-также. На обеих машинах установлен пакет обновления 1 для Microsoft Office 2013 (KB2850036).
Горд Томпсон
4
Для Office 2010 Pro Plus (SP2) нам нужно было использовать {90140000-0011-0000-0000-0000000FF1CE}пакетный скрипт. Обратите внимание, {9014...нет{9114..}
AdamsTips
2
Я исправил официальное обновление, чтобы решить проблему, но я все еще получаю сообщение об ошибке. Кто-нибудь еще получил эту проблему?
user218076
33

Самое простое решение

Для моих пользователей ждать выпуска исправлений от Microsoft почти месяц до 10 декабря не вариант. Также не происходит удаление оскорбительного обновления Microsoft на нескольких заблокированных правительством рабочих станциях.

Мне нужно применить обходной путь, но я не совсем в восторге от того, что предложила Microsoft - создание и замена запроса для каждой таблицы.

Решение состоит в том, чтобы заменить имя таблицы простым (SELECT * FROM Table)запросом непосредственно в UPDATEкоманде. Это не требует создания и сохранения тонны дополнительных запросов, таблиц или функций.

ПРИМЕР:

Перед:

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

После:

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

Это должно быть намного проще реализовать в нескольких базах данных и приложениях (и в дальнейшем откате).

Джо Маринуччи
источник
20

Это не проблема обновления Windows, а проблема, появившаяся в выпуске November Patch Tuesday Office. Изменения, устраняющие уязвимость системы безопасности, приводят к тому, что некоторые допустимые запросы сообщаются как поврежденные. Поскольку изменение было исправлением безопасности, оно влияет на ВСЕ сборки Office, включая 2010, 2013, 2016, 2019 и O365.

Ошибка была исправлена ​​во всех каналах, но время доставки будет зависеть от того, на каком канале вы находитесь.

В выпусках MSI 2010, 2013 и 2016 гг. С корпоративной лицензией 2019 г. и полугодовом канале O365 исправление будет в сборке с декабрьским исправлением во вторник, 10 декабря. Для O365, ежемесячного канала и инсайдеров это исправление будет исправлено когда октябрьская вилка будет выпущена, в настоящее время запланировано на 24 ноября.

Для полугодового канала ошибка была введена в 11328.20468, который был выпущен 12 ноября, но не распространяется на всех сразу. Если вы можете, вы можете отложить обновление до 10 декабря.

Эта проблема возникает для запросов на обновление одной таблицы с указанными критериями (поэтому не следует затрагивать запросы других типов, а также запросы, которые обновляют все строки таблицы, или запрос, который обновляет набор результатов другого запроса). Учитывая это, самый простой обходной путь в большинстве случаев - изменить запрос на обновление, чтобы обновить другой запрос, который выбирает все из таблицы, вместо непосредственного обновления запроса.

Т.е. если у вас есть запрос вроде:

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

Затем создайте новый запрос (Query1), определенный как:

Select * from Table1;

и обновите исходный запрос:

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

Официальная страница: Ошибка доступа: «Запрос поврежден»

Gustav
источник
13
Вы на самом деле говорите прямо, что мы переходим к сотням тысяч строк кода, развернутых в нескольких приложениях, и исправляем все обновления SQL, которые просто обновляют ряд данных? Я полагаю, если вы пишете новый запрос сегодня и сейчас, то такой обходной путь возможен. Но для существующего кода и приложений идея, что обновления SQL должны быть изменены, конечно, не практический подход к решению проблем любым возможным способом.
Альберт Д. Каллал
5
@ AlbertD.Kallal, вы должны знать из списка MVP, что я просто ссылаюсь на объяснение источника проблемы. Как решить проблему, зависит от вас и от того, что может соответствовать вашему сценарию. Метод, описанный здесь, является лишь одним из нескольких.
Густав
1
@ AlbertD.Kallal Разве это не должно переименовывать таблицы и создавать QueryDefs со старым именем таблицы? (Я
ComputerVersteher
Вы можете сделать это без программирования, например, переименуйте таблицу «users» в «userst», а затем создайте имя запроса «users» - и тогда это будет работать без программирования…
Zvi
9
@ AlbertD.Kallal: Я разделяю вашу боль - если бы это была ошибка, затрагивающая библиотеку времени выполнения VC, я не думаю, что MS отложила бы исправление на один месяц и предложила бы обходной путь «переписать, перекомпилировать и заново развернуть». (Чтобы быть справедливым, они быстро исправили и выпустили выпуск VBA в конце августа.) Но давайте не будем стрелять в мессенджера - Густав, похоже, не сотрудник MS. Будем надеяться, что они пересмотрят и выпустят патч раньше; в конце концов, это также влияет на приложения, написанные на других языках, которые просто используют механизм доступа к БД .
Хайнци
15

Временное решение этой проблемы зависит от используемой версии Access:
Обновление Access 2010, удаление KB4484127 Обновление
Access 2013, удаление KB4484119 Обновление
Access 2016, удаление KB4484113
Access 2019, ЕСЛИ ТРЕБУЕТСЯ (tbc). Понизьте версию 1808 (сборка 10352.20042) до версии 1808 (сборка 10351.20054). Обновление
Office 365 ProPlus с версии 1910 (сборка 12130.20344) до предыдущей сборки см. По адресу https://support.microsoft.com/en-gb/help/2770432/. как к Revert к ан-ранее-версии-оф-офис-2013 или офис-2016-CLIC

Грант
источник
Я удалил его, но он переустановил при следующем запуске Windows. Как вы препятствуете его переустановке?
dsteele
5
@dsteele Если версия MSI и нет WSUS, используйте support.microsoft.com/en-us/help/3073930/… средство устранения неполадок. На CTR отключите обновления в Office-Account-Settings ..
ComputerVersteher
5

Мы и наши клиенты боролись с этим последние два дня и, наконец, написали статью, в которой подробно обсуждали проблему и некоторые решения: http://fmsinc.com/MicrosoftAccess/Errors/query_is_corrupt/

В нем содержатся наши выводы о том, что это влияет на решения Access при выполнении запросов на обновление локальных таблиц, связанных таблиц Access и даже связанных таблиц SQL Server.

Это также влияет на решения, не относящиеся к Microsoft Access, использующие Access Database Engine (ACE) для подключения к базам данных Access с использованием ADO. К ним относятся приложения Visual Studio (WinForm), приложения VB6 и даже веб-сайты, которые обновляют базы данных Access на компьютерах, на которых никогда не было установлено приложение Access или Office.

Этот сбой может даже повлиять на приложения Microsoft, которые используют ACE, такие как PowerBI, Power Query, SSMA и т. Д. (Не подтверждено), и, конечно, другие программы, такие как Excel, PowerPoint или Word, использующие VBA для изменения баз данных Access.

В дополнение к очевидному удалению обновлений безопасности, вызывающих проблемы, мы также включаем некоторые параметры, которые невозможно удалить из-за разрешений или распространения приложений Access для внешних клиентов, чьи компьютеры находятся вне вашего контроля. Это включает в себя изменение всех запросов на обновление и распространение приложений Access с использованием Access 2007 (для розничной продажи или среды выполнения), поскольку обновления безопасности не влияют на эту версию.

LukeChung-FMS
источник
4

Используйте следующий модуль для автоматической реализации предложенного Microsoft обходного решения (используя запрос вместо таблицы). В качестве меры предосторожности, сначала сделайте резервную копию вашей базы данных.

Используйте, AddWorkaroundForCorruptedQueryIssue()чтобы добавить обходной путь и RemoveWorkaroundForCorruptedQueryIssue()удалить его в любое время.

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

Вы можете найти последний код в моем репозитории GitHub .

AddWorkaroundForCorruptedQueryIssue()добавит суффикс _Tableко всем несистемным таблицам, например, таблица IceCreamsбудет переименована в IceCreams_Table.

Он также создаст новый запрос, используя исходное имя таблицы, который выберет все столбцы переименованной таблицы. В нашем примере запрос будет назван IceCreamsи будет выполнять SQL select * from [IceCreams_Table].

RemoveWorkaroundForCorruptedQueryIssue() делает обратные действия.

Я проверил это со всеми видами таблиц, включая внешние таблицы, не относящиеся к MDB (например, SQL Server). Но имейте в виду, что использование запроса вместо таблицы может привести к неоптимизированным запросам, выполняемым к серверной базе данных в определенных случаях, особенно если ваши исходные запросы, которые использовали таблицы, либо низкого качества, либо очень сложные.

(И, конечно же, в зависимости от вашего стиля кодирования, в вашем приложении также возможно что-то сломать. Поэтому после проверки того, что исправление обычно работает для вас, никогда не будет плохой идеей экспортировать все ваши объекты в виде текста и использовать некоторые находки и замены Волшебство, гарантирующее, что любые вхождения имен таблиц будут выполняться для запросов, а не для таблиц.)

В моем случае это исправление работает в основном без каких-либо побочных эффектов, мне просто нужно было вручную переименовать его USysRibbons_Tableобратно USysRibbons, поскольку я не помечал его как системную таблицу при создании в прошлом.

lauxjpn
источник
Мне нравится, что вы определяете системную таблицу с помощью TableDef.Attributesи копируете ее в мой ответ;) и функция отмены является хорошей идеей (но старое и новое имя должны храниться в таблице, поскольку в зависимости от того, нет таблиц с суффиксом до переименования). Некоторые другие части неисправны (например, таблицы могут заканчиваться суффиксом, или newname уже используется или On Error Resume Nextне обрабатывает ошибки позже). Вы знаете RubberduckVBA ? Этот плагин может проверить ваш код и дает хорошие предложения по улучшению, помимо всех других функций.
ComputerVersteher
И вы должны указать на ошибки, которые может вызвать наш подход (см. Комментарии @Erics к моему ответу)
ComputerVersteher
Ах, я не видел, что здесь уже был подобный ответ, так что спасибо за обзор! Суффикс определяется в своей собственной константе, поэтому его можно легко изменить в случае, если уже определен уже существующий объект, который уже использует суффикс. В противном случае сценарий работает как есть, но любой должен почувствовать желание изменить его в соответствии со своими индивидуальными потребностями. Скрипт был протестирован на довольно больших проектах (более 400 таблиц), включая внешние / связанные таблицы с различными внешними источниками базы данных. Я не знал про Rubberduck (только про MZ-Tools). Я обязательно проверю их!
Lauxjpn
3

Для тех, кто хочет автоматизировать этот процесс с помощью PowerShell , я нашел несколько ссылок, которые могут оказаться полезными:

Обнаружение и удаление оскорбительных обновлений

Здесь есть скрипт PowerShell, доступный по адресу https://www.arcath.net/2017/09/office-update-remover, который ищет в реестре конкретное обновление Office (передается как число в КБ) и удаляет его с помощью вызова msiexec.exe, Этот сценарий анализирует оба идентификатора GUID из разделов реестра, чтобы создать команду для удаления соответствующего обновления.

Одним из изменений, которое я бы предложил, было бы использование /REBOOT=REALLYSUPPRESSописанного в разделе Как удалить KB4011626 и других обновлений Office (дополнительная ссылка: https://docs.microsoft.com/en-us/windows/win32/msi/uninstall-patches ). Командная строка, которую вы строите, выглядит следующим образом:

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

Команда для запуска скрипта будет выглядеть примерно так:

OfficeUpdateRemover.ps1 -kb 4484127

Запретить установку обновлений

Рекомендуемый подход, похоже, скрывает обновление . Очевидно, что это можно сделать вручную, но есть некоторые сценарии PowerShell, которые могут помочь в автоматизации. Эта ссылка: https://www.maketecheasier.com/hide-updates-in-windows-10/ описывает процесс подробно, но я подведу итоги здесь.

  1. Установите модуль обновления Windows PowerShell .
  2. Используйте следующую команду, чтобы скрыть обновление по номеру КБ:

    Hide-WUUpdate -KBArticleID KB4484127

Надеюсь, это поможет кому-то еще.

AdamsTips
источник
3

VBA-скрипт для MS-решения:

Рекомендуется удалить исправленное обновление, если это возможно (если не попробовать мой код), по крайней мере для версий MSI. Смотрите ответ https://stackoverflow.com/a/58833831/9439330 .

Для версий CTR (Click-To-Run) необходимо удалить все обновления Office за ноябрь, что может вызвать серьезные проблемы с безопасностью (не уверен, будут ли удалены какие-либо критические исправления).

Из комментариев @ Эрика:

  • Если вы используете Table.Tablenameдля связывания форм, они освобождаются, так как прежнее имя таблицы теперь является именем запроса !.
  • OpenRecordSet(FormerTableNowAQuery, dbOpenTable) потерпит неудачу (так как теперь это запрос, а не таблица)

Внимание! Просто быстрая проверка на Northwind.accdb на Office 2013 x86 CTR Нет гарантии!

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

Для тестирования:

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
источник
4
Обратите внимание, что этот обходной путь разрушит подчиненные формы, привязанные к таблицам (необходимо выполнить привязку к запросам) и коду, работающему с tabledefs с жестко закодированным именем таблицы. Используйте с большой осторожностью, есть вероятность, что это исправит одну ошибку только для создания двух новых, в зависимости от того, что делает ваше приложение.
Эрик А
@ErikA Конечно только обходной путь, но я могу связать Inventory to reorder Subform for Homeс Inventoryтаблицей в Homeформе, без проблем. Даже не рекомендуется привязывать формы к запросам, а не к таблицам (не привязывается ли к таблицам как Select * From table?).
ComputerVersteher
2
Если я связываю подчиненную форму с таблицей, я обычно делаю это, используя Table.TableNameобозначения. Если вы делаете SELECT * FROM TableNameвместо этого, вы, конечно, в порядке. Но если вы используете Table.TableName, ваша подчиненная форма станет несвязанной, если вы переименуете таблицу.
Эрик А
@ErikA: это правда. Есть ли польза от этого?
ComputerVersteher
3
Не настолько, насколько я знаю, кроме того, что это более кратко. Однако есть существенное преимущество TableDefs!MyTableName.OpenRecordset(dbOpenTable)(поддержка поиска по индексу), которое я также склонен использовать, и это также приведет к ошибкам при вашем подходе
Эрик
2

Я заменил currentDb.Executeи Docmd.RunSQLс вспомогательной функцией. Это может предварительно обработать и изменить оператор SQL, если какой-либо оператор обновления содержит только одну таблицу. У меня уже есть dualтаблица (одна строка, один столбец), поэтому я выбрал опцию fakeTable.

Примечание : это не изменит ваши объекты запроса. Это поможет только выполнению SQL через 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.

Это всего лишь концепция (If it's a single table update modify the sql before execution). Приспособьте это согласно своим потребностям. Этот метод не создает запросы на замену для каждой таблицы (что может быть самым простым способом, но имеет свои недостатки. Т.е. проблемы с производительностью)

+ Очки: Вы можете продолжать использовать этот помощник даже после того, как MS исправит ошибку, это ничего не изменит. В случае, если будущее принесет другую проблему, вы готовы к pre-processвашему SQL в одном месте. Я не пошел на метод удаления обновлений, потому что для этого требуется доступ администратора + потребуется слишком много времени, чтобы получить всех на правильную версию +, даже если вы удалите, групповая политика некоторых конечных пользователей снова устанавливает последнее обновление. Вы вернулись к той же проблеме.

Если у вас есть доступ к исходному коду, use this methodи вы на 100% уверены, что проблема не возникнет ни у какого конечного пользователя.

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

Теперь просто CTRL+F

Поиск и замена docmd.RunSQLнаhelper.Execute

Поиск и замена [currentdb|dbengine|or your dbobject].executeнаhelper.execute

радоваться, веселиться!

Криш
источник
0

Хорошо, я тоже буду здесь, потому что, хотя эта ошибка была исправлена, это исправление еще не заполнилось полностью на различных предприятиях, где конечные пользователи могут не иметь возможности обновляться (например, мой работодатель ...)

Вот мой обходной путь для DoCmd.RunSQL "UPDATE users SET uname= 'bob' WHERE usercode=1". Просто закомментируйте ошибочный запрос и введите код ниже.

    '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

Я не могу сказать, что это красиво, но это делает работу.

Chaosbydesign
источник