In OleDb parameters are positional. They are not recognized by their name. (See the Remarks section on OleDbCommand.Parameters collection)
The parameter placeholder for @CRSID appears as the last one in your query, but the first OleDbCommand.Parameter is, named for, and filled with the value for @CRSID.
This means that all your parameters are used for the wrong fieldfields or condition and you end up with a where clause totally wrong. The command searches the CRSID field with the value of FirstName (and, pretty sure, it cannot find any match).
The correct code for your sql is
Update NewPMS SET LastName = @LastName, FirstName = @Firstname WHERE CRSID = @CRSID .... cmd.Parameters.AddRange(New OleDb.OleDbParameter() _ { New OleDb.OleDbParameter With {.ParameterName = "@LastName", .DbType = DbType.String}, New OleDb.OleDbParameter With {.ParameterName = "@FirstName", .DbType = DbType.String} New OleDb.OleDbParameter With {.ParameterName = "@CRSID", .DbType = DbType.Int32}, } ) cmd.Parameters(0).Value = drCurrent("LastName") cmd.Parameters(1).Value = drCurrent("FirstName") cmd.Parameters(2).Value = drCurrent("CRSID") As a side note, you should move the initialization of the OleDbCommand outside the loop, create the empty parameters and open the connection. Inside the loop, just set the values for the parameters from the current row and execute the command. (Don't close the connection until the end of the loop of course). This logic is a simple better logicand without side effects that, but it could be significantgive a slight better performance if you have many rows.