如何合并这两个 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])
...
我在 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])
...