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

时间:2019-03-26 00:00:18

标签: sql vba ms-access access-vba ms-access-2016

我在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一起使用,但它只是使用无效的语法对我造成了错误。

2 个答案:

答案 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;