我在VBA中使用了两个SQL查询,我相信它们可以在一个查询中完成,但是我无法使其正常工作。我想将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一起使用,但它只是使用无效的语法对我造成了错误。
答案 0 :(得分:1)
是的,可以通过一个查询来实现,如下所示
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
答案 1 :(得分:1)
此问题是对所描述的错误和给定代码的解答,尽管从技术上讲它不能回答单个SQL语句的请求。我开始添加评论,但是当此答案框允许一次高效地表达所有内容时,这太麻烦了。
首先,引用CurrentDb
实际上不是对单个对象实例的基本引用。相反,它更像是一个函数调用,该函数生成基础数据库对象的新的唯一“克隆”。一遍又一遍地调用它会导致内存泄漏,至少是非常低效的。有关详细信息,请参见MS docs。
尽管给定的代码很短,但并不甜。它不仅会重复创建新的数据库对象,而且还会重复执行一条SQL语句来更新每次我认为是一行的内容。这还需要每次重新生成SQL字符串。
即使重复执行SQL语句是一个有效的选择,也有更好的方法来执行此操作,例如创建带有参数的临时(内存中)QueryDef对象。然后,每次循环迭代仅重置参数并执行相同的准备好的SQL语句。
但是在这种情况下,将要更新的表加载到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上生成唯一值,但是很明显,不需要对不具有{{1}的值进行分组(和求和) }。查询会更有效,例如
Tbl_VCodes.IsApd = 'OFF'
顺便说一句,您可以考虑实现与上面所示相同的临时QueryDef模式,然后将第一个WHERE表达式更改为类似的
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;