The MS Access Jet/ACE db engine does not support UPDATEs via subqueries (among other limitations).
You have three primary options:
Option 1: Temporary Table
Run your subquery as a "Make Table" query first:
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
Then use the resulting temporary table to do your update:
UPDATE Details SET Details.PersonId = t.Person
FROM Details INNER JOIN temp_T AS t ON Details.MachineId = t.MachineId
Option 2: Select Query and Domain Aggregate Function
Create and save a select query and then use a DLookup when setting the value in your UPDATE query. You need to save the select query because the stock DLookup function does not allow you to specify a sort order.
SELECT Call.MachineId, Visit.PersonId
FROM Call INNER JOIN Visit ON Call.CallId = Visit.CallId
ORDER BY Visit.Date DESC
Save the above to a query named LastCalledTech. Then change your UPDATE query to:
UPDATE Details SET Details.PersonId =
DLookup("PersonID", "LastCalledTech", "MachineID=" & Details.MachineID)
Option 3: Modified DLookup() Custom Function
Allen Browne wrote an "extended" DLookup function that allows you to specify a sort order. I further modified the function slightly to allow passing in an arbitrary SELECT statement (not just a table or query name). We don't actually need the sort parameter in this case because it is more efficient to simply include it in the SELECT SQL string. Using this function (which I've posted below), you would execute the following UPDATE query:
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)
And here is the modified function:
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