Как я могу объединить эти два запроса SQL (Access / VBA) - PullRequest
0 голосов
/ 26 марта 2019

Я использую два SQL-запроса в VBA, которые, как я полагаю, могут быть выполнены в одном, но я не могу заставить его работать. Я хочу превратить часть VBA в Запрос вне VBA, VBA продолжает ломать мой файл из-за объема данных, которые он обрабатывает. (Под разрывом я подразумеваю, что он выдает сообщение «этот файл не является действительной базой данных», что делает файл поврежденным). Я ищу эту ошибку, но все, что я нашел, не было связано с взломом из-за кода VBA.

В любом случае, вот два запроса, выполненных с VBA.

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 & "#)
GROUP BY ET.VerintEID, Tbl_VCodes.IsApd
HAVING Tbl_VCodes.IsApd = ""OFF"";

Я зацикливаю эти результаты для обновления таблицы.

Do While Not .EOF
    SQL = "UPDATE Tbl_AttendanceByAgent SET EXC = " & recSet.Fields(1).Value & _
        " WHERE VerintID = '" & recSet.Fields(0).Value & "'"
    CurrentDb.Execute SQL
    .MoveNext
Loop

Я знаю, что могу сохранить результаты первого запроса в таблицу, и без циклов я могу обновить основную таблицу другим запросом SQL, но я верю, что это можно сделать на одном SQL. Я попытался использовать UPDATE с SELECT для первого запроса, но он просто выдал ошибку из-за неправильного синтаксиса.

Ответы [ 2 ]

1 голос
/ 26 марта 2019

Этот вопрос является ответом на описанные ошибки и данный код, хотя технически он не отвечает на запрос одного оператора 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])
...
1 голос
/ 26 марта 2019

Да, это может быть достигнуто за один запрос, как показано ниже

UPDATE Tbl_AttendanceByAgent 
SET Tbl_AttendanceByAgent.EXC = t2.Exeptions
from Tbl_AttendanceByAgent t1
inner join (
    SELECT ET.VerintEID AS EID, Sum(ET.ExceptMin)/60 AS Exeptions
    FROM Tbl_VExceptTime AS ET
    INNER JOIN Tbl_VCodes as TV ON ET.Exception = TV.Exception    
    WHERE (ET.ExceptDate Between #" & sDate & "# And #" & eDate & "#)
    GROUP BY ET.VerintEID, TV.IsApd
    HAVING Tbl_VCodes.IsApd = 'OFF'
) AS t2 on t2.EID = t1.VerintID 

Примечание: Я полагаю, вы замените sDate, eDate на значения в вашем коде

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...