Этот вопрос является ответом на описанные ошибки и данный код, хотя технически он не отвечает на запрос одного оператора SQL. Я начал добавлять комментарий, но это слишком утомительно, когда в этом поле для ответа все сразу можно эффективно выразить.
Прежде всего, ссылка на CurrentDb
на самом деле НЕ является базовой ссылкой на один экземпляр объекта. Скорее это больше похоже на вызов функции, который генерирует новый, уникальный «клон» базового объекта базы данных. Известно, что повторный вызов вызывает утечки памяти и, по крайней мере, очень неэффективен. Подробнее см. MS документы .
Хотя данный код короткий, он не сладкий. Мало того, что он многократно создает новые объекты базы данных, он также многократно выполняет оператор SQL, чтобы обновлять то, что, как я полагаю, является единственной строкой каждый раз. Это также влечет за собой восстановление строки SQL каждый раз.
Даже если выполнение оператора SQL неоднократно было эффективным вариантом, существуют более эффективные способы сделать это, например, создать временный (в памяти) объект QueryDef с параметрами. Затем каждая итерация цикла просто сбрасывает параметры и выполняет один и тот же подготовленный оператор SQL.
Но в этом случае на самом деле может быть более эффективно загрузить обновляемую таблицу в набор DAO.Recordset, затем использовать набор записей в памяти для поиска совпадения, а затем использовать набор записей для обновления строки.
Я подозреваю, что решение нескольких из этих проблем сделает ваш код VBA жизнеспособным.
Dim db as Database
Set db = CurrentDb 'Get just a single instance and reuse
Dim qry as QueryDef
SQL = "PARAMETERS pEXC Text ( 255 ), pID Long; " & _
" UPDATE Tbl_AttendanceByAgent SET EXC = pEXC " & _
" WHERE VerintID = pID"
set qry = db.CreateQueryDef("", SQL)
'With recSet '???
Do While Not .EOF
qry.Parameters("pEXC") = recSet.Fields(1).Value
qry.Parameters("pID") = recSet.Fields(0).Value
qry.Execute
.MoveNext
Loop
'End With recSet '???
'OR an alternative
Dim recUpdate As DAO.Recordset2
Set recUpdate = db.OpenRecordset("Tbl_AttendanceByAgent", DB_OPEN_TABLE)
Do While Not .EOF
recUpdate.FindFirst "VerintID = " & recSet.Fields(0).Value
If Not recUpdate.NoMatch Then
recUpdate.Edit
recUpdate.Fields("EXC") = recSet.Fields(1).Value
recUpdate.Update
End If
.MoveNext
Loop
Я понял, комментируя ответ Гро, что агрегатные предложения исходного запроса будут генерировать уникальные значения EID, но тогда становится очевидным, что нет необходимости группировать (и суммировать) значения, которые не имеют Tbl_VCodes.IsApd = 'OFF'
. Запрос будет более эффективным, как
SELECT ET.VerintEID AS EID, Sum(ET.ExceptMin)/60 AS Exeptions
FROM Tbl_VExceptTime AS ET
INNER JOIN Tbl_VCodes ON ET.Exception = Tbl_VCodes.Exception
WHERE (ET.ExceptDate Between #" & sDate & "# And #" & eDate & "#)
AND Tbl_VCodes.IsApd = 'OFF'
GROUP BY ET.VerintEID;
Кстати, вы могли бы рассмотреть возможность реализации того же временного шаблона QueryDef, как я показал выше, тогда вы бы изменили первое выражение WHERE на что-то вроде
PARAMETERS PsDate DateTime, PeDate DateTime;
...
WHERE (ET.ExceptDate Between [PsDate] And [PeDate])
...