MS Access Jet/ACE db 引擎不支持通过子查询进行更新(除其他限制外)。
您有三个主要选择:
选项 1:临时表
首先将您的子查询作为“生成表”查询运行:
SELECT Call.MachineId, Visit.PersonId AS Person INTO temp_T
FROM Call INNER JOIN Visit ON Call.CallId = Visit.CallId
ORDER BY Visit.Date DESC
然后使用生成的临时表进行更新:
UPDATE Details SET Details.PersonId = t.Person
FROM Details INNER JOIN temp_T AS t ON Details.MachineId = t.MachineId
选项 2:选择查询和域聚合函数
创建并保存选择查询,然后在 UPDATE 查询中设置值时使用 DLookup。您需要保存选择查询,因为 stock DLookup 函数不允许您指定排序顺序。
SELECT Call.MachineId, Visit.PersonId
FROM Call INNER JOIN Visit ON Call.CallId = Visit.CallId
ORDER BY Visit.Date DESC
将上述内容保存到名为 LastCalledTech 的查询中。然后将您的 UPDATE 查询更改为:
UPDATE Details SET Details.PersonId =
DLookup("PersonID", "LastCalledTech", "MachineID=" & Details.MachineID)
选项 3:修改 DLookup() 自定义函数
Allen Browne 编写了一个“扩展的”DLookup 函数,允许您指定排序顺序。我进一步稍微修改了函数以允许传入任意 SELECT 语句(不仅仅是表或查询名称)。在这种情况下,我们实际上不需要 sort 参数,因为将其简单地包含在 SELECT SQL 字符串中会更有效。使用此函数(我已在下面发布),您将执行以下 UPDATE 查询:
UPDATE Details SET Details.PersonId =
ELookup("PersonID", "SELECT Call.MachineId, Visit.PersonId
FROM Call INNER JOIN Visit ON
Call.CallId = Visit.CallId
ORDER BY Visit.Date DESC",
"MachineID=" & Details.MachineID)
这是修改后的功能:
Public Function ELookup(Expr As String, Domain As String, Optional Criteria As Variant, _
Optional OrderClause As Variant) As Variant
On Error GoTo Err_ELookup
'Purpose: Faster and more flexible replacement for DLookup()
'Arguments: Same as DLookup, with additional Order By option.
'Return: Value of the Expr if found, else Null.
' Delimited list for multi-value field.
'Author: Allen Browne. allen@allenbrowne.com
'Updated: December 2006, to handle multi-value fields (Access 2007 and later.)
' {by mwolfe02} Add parentheses to allow passing arbitrary SELECT statements
'Examples:
' 1. To find the last value, include DESC in the OrderClause, e.g.:
' ELookup("[Surname] & [FirstName]", "tblClient", , "ClientID DESC")
' 2. To find the lowest non-null value of a field, use the Criteria, e.g.:
' ELookup("ClientID", "tblClient", "Surname Is Not Null" , "Surname")
'Note: Requires a reference to the DAO library.
Dim db As DAO.Database 'This database.
Dim rs As DAO.Recordset 'To retrieve the value to find.
Dim rsMVF As DAO.Recordset 'Child recordset to use for multi-value fields.
Dim varResult As Variant 'Return value for function.
Dim strSql As String 'SQL statement.
Dim strOut As String 'Output string to build up (multi-value field.)
Dim lngLen As Long 'Length of string.
Const strcSep = "," 'Separator between items in multi-value list.
'Initialize to null.
varResult = Null
'Build the SQL string.
strSql = "SELECT TOP 1 " & Expr & " FROM (" & Domain & ")"
If Not IsMissing(Criteria) Then
strSql = strSql & " WHERE " & Criteria
End If
If Not IsMissing(OrderClause) Then
strSql = strSql & " ORDER BY " & OrderClause
End If
strSql = strSql & ";"
'Lookup the value.
Set db = DBEngine(0)(0)
Set rs = db.OpenRecordset(strSql, dbOpenForwardOnly)
If rs.RecordCount > 0 Then
'Will be an object if multi-value field.
If VarType(rs(0)) = vbObject Then
Set rsMVF = rs(0).Value
Do While Not rsMVF.EOF
If rs(0).Type = 101 Then 'dbAttachment
strOut = strOut & rsMVF!FileName & strcSep
Else
strOut = strOut & rsMVF![Value].Value & strcSep
End If
rsMVF.MoveNext
Loop
'Remove trailing separator.
lngLen = Len(strOut) - Len(strcSep)
If lngLen > 0& Then
varResult = Left(strOut, lngLen)
End If
Set rsMVF = Nothing
Else
'Not a multi-value field: just return the value.
varResult = rs(0)
End If
End If
rs.Close
'Assign the return value.
ELookup = varResult
Exit_ELookup:
Set rs = Nothing
Set db = Nothing
Exit Function
Err_ELookup:
MsgBox Err.Description, vbExclamation, "ELookup Error " & Err.number
Resume Exit_ELookup
End Function