如何合并这两个 SQL 查询 (Access/VBA)

How can I combine these two SQL queries (Access/VBA)

我在 VBA 中使用两个 SQL 查询,我相信它们可以在一个查询中完成,但我无法让它工作。我想将 VBA 部分变成 VBA 之外的查询,VBA 由于它处理的数据量不断破坏我的文件。 (我所说的中断是指它给出一条消息,说 "this file is not a valid database" 呈现文件已损坏)。我搜索了那个错误,但我发现的所有内容都与中断无关,因为 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"";

我循环这些结果来更新 table。

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

我知道我可以将第一个查询的结果保存到 table 中并且无需循环我可以用另一个 SQL 查询更新主 table,但我相信它可以在单个 SQL 上完成。我已经尝试使用带有第一个查询的 SELECT 的更新,但它只是用无效的语法向我展示了错误。

是的,这可以在一个查询中实现,如下所示

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

这个问题是对所描述的错误和给定代码的回答,尽管它在技术上不回答对单个 SQL 语句的请求。我开始添加评论,但是当这个答案框允许一次高效地表达所有内容时,这太乏味了。

首先,引用CurrentDb实际上不是对单个对象实例的基本引用。相反,它更像是一个函数调用,它生成一个新的、唯一的 "clone" 底层数据库对象。众所周知,一遍又一遍地调用它会产生内存泄漏,至少效率很低。有关详细信息,请参阅 MS docs

虽然给出的代码很短,但并不甜美。它不仅重复创建新的数据库对象,而且重复执行 SQL 语句来更新我假设每次都是单行的内容。这还需要每次重新生成 SQL 字符串。

即使重复执行 SQL 语句是一个有效的选择,也有更好的方法可以做到这一点,比如创建一个带参数的临时(内存中)QueryDef 对象。然后每个循环迭代只重置参数并执行相同的准备好的 SQL 语句。

但在这种情况下,将正在更新的 table 加载到 DAO.Recordset,然后使用内存中的 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

我在评论 Gro 的回答时意识到,原始查询的聚合子句将在 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])
...