Access VBA ODBC connection failed - sql-server

I have an Access Frontend with a SQL Server backend.
On one of the forms, there is a bit of VBA to keep an "Audit Log" of the changes.
In one procedure there are these 2 bits of code, the first works, but the second gives an error
Working:
sSQL = "DELETE FROM [dbo_EventReport_Audit_Temp_Before];"
CurrentProject.Connection.Execute sSQL
Not working a few lines down:
sSQL = "INSERT INTO [dbo_EventReport_Audit_Temp_Before] (<TABLE COLUMNS>) SELECT <TABLE COLUMNS> FROM [dbo_EventReport] WHERE ((Event_ID)= <EVENT_ID>");"
CurrentProject.Connection.Execute sSQL
So the first statement deletes any records in the table. This works fine, as I've inserted dummy data and stepped through the code and seen it be deleted.
But the second statement causes an error:
Error -2147467259: ODBC--connection to 'EventsDB' failed.
Anyone any idea why the first statement works ok, but the second fails?
Extracting the value of sSQL for the second statement and manually running it through an SQL Query in Access inserts the data into the table.
EDIT:
I didn't want to post the full statement as it's a bit of a monster. But here is is:
sSQL = "INSERT INTO " & sAudTmpTable & " ( [audType], [audDate], [audUser], [Event_Number], [Event_ID], " & _
"[Received_Date], [Response_Date], [Site], [Server], [Workstation], [Software_Version], [Data_Version], " & _
"[Description], [Test_Description], [Company], [Observed_By], [Observed_Date], [Tested_By], [AssignedTo], " & _
"[Tested_Date], [Test_Result], [Ind_Tested_By], [Ind_Tested_On], [Ind_Test_Result], [Reviewed_By], " & _
"[Actioned_Date], [Review_Date], [Review_Result], [Completed_By], [Completed_Date], [Closed_By], " & _
"[Closed_Date], [Exclude], [Category], [State], [Event_Responsibility], [Probability], [WIP_Number], " & _
"[OriginalWIP], [Severity], [Blocked], [Block_Description], [Tags], [Work], [TaskID], [EventType], " & _
"[DefectType], [known_issue_impact], [known_issue_description], [Operator_Notes], [BugWIP], " & _
"[SupplierName], [SupplierCompany], [Simulator], [ATSTest], [FixPriority] ) " & _
"SELECT '" & EditOrInsert & "' AS Expr1, '" & DateTime & "', '" & User & "', [Event_Number], [Event_ID], " & _
"[Received_Date], [Response_Date], [Site], [Server], [Workstation], [Software_Version], [Data_Version], " & _
"[Description], [Test_Description], [Company], [Observed_By], [Observed_Date], [Tested_By], [AssignedTo], " & _
"[Tested_Date], [Test_Result], [Ind_Tested_By], [Ind_Tested_On], [Ind_Test_Result], [Reviewed_By], " & _
"[Actioned_Date], [Review_Date], [Review_Result], [Completed_By], [Completed_Date], [Closed_By], " & _
"[Closed_Date], [Exclude], [Category], [State], [Event_Responsibility], [Probability], [WIP_Number], " & _
"[OriginalWIP], [Severity], [Blocked], [Block_Description], [Tags], [Work], [TaskID], [EventType], " & _
"[DefectType], [known_issue_impact], [known_issue_description], [Operator_Notes], [BugWIP], " & _
"[SupplierName], [SupplierCompany], [Simulator], [ATSTest], [FixPriority] " & _
"FROM [" & sTable & "] WHERE ((" & sKeyField & ")=" & lngKeyValue & ");"

You reported this attempt fails ...
CurrentProject.Connection.Execute sSQL
... but this works using the same sSQL statement ...
CurrentDb.Execute sSQL, dbFailOnError + dbSeeChanges
CurrentProject.Connection.Execute is an ADO method. CurrentDb.Execute is a DAO method. The two methods are similar, but not the same.
One important difference is the ADO version is more likely to fail when the SQL statement includes reserved words as object (table, field, etc.) names; DAO is more forgiving about problem names.
But there are other differences, and it is not possible to determine which of them was the key factor for an INSERT statement we haven't seen. ;-)

Related

Incorrect Syntax Error running SQL command in VB.NET

I have a SQL command that I'm running in VB.NET... I've written this type of command countless times, however, I'm getting an error when trying to process the command below:
Dim VIconn As New SqlConnection("Data Source=MBSRVERP01;Initial Catalog=MBUk;Integrated Security=True")
Dim CMDoperation As SqlCommand = New SqlCommand()
CMDoperation.Connection = VIconn
CMDoperation.CommandText = ("INSERT INTO PRJCREATION.dbo.OPERATION_CO (WORKORDER_TYPE, WORKORDER_BASE_ID, WORKORDER_LOT_ID, WORKORDER_SPLIT_ID, WORKORDER_SUB_ID, SEQUENCE_NO, RESOURCE_ID, SETUP_HRS, " _
& "RUN, RUN_TYPE, LOAD_SIZE_QTY, RUN_HRS, MOVE_HRS, TRANSIT_DAYS, SERVICE_ID, SCRAP_YIELD_PCT, SCRAP_YIELD_TYPE, FIXED_SCRAP_UNITS, MINIMUM_MOVE_QTY, CALC_START_QTY, " _
& "CALC_END_QTY, COMPLETED_QTY, DEVIATED_QTY, ACT_SETUP_HRS, ACT_RUN_HRS, STATUS, SETUP_COMPLETED, SERVICE_BEGIN_DATE, CLOSE_DATE, OPERATION_TYPE, DRAWING_ID, DRAWING_REV_NO, " _
& "OVERRIDE_QTYS, BEGIN_TRACEABILITY, CAPACITY_USAGE_MAX, CAPACITY_USAGE_MIN, TEST_ID, SPC_QTY, SCHED_START_DATE, SCHED_FINISH_DATE, COULD_FINISH_DATE, ISDETERMINANT, " _
& "SETUP_COST_PER_HR, RUN_COST_PER_HR, RUN_COST_PER_UNIT, BUR_PER_HR_SETUP, BUR_PER_HR_RUN, BUR_PER_UNIT_RUN, SERVICE_BASE_CHG, BUR_PERCENT_SETUP, BUR_PERCENT_RUN, " _
& "BUR_PER_OPERATION, EST_ATL_LAB_COST, EST_ATL_BUR_COST, EST_ATL_SER_COST, REM_ATL_LAB_COST, REM_ATL_BUR_COST, REM_ATL_SER_COST, ACT_ATL_LAB_COST, ACT_ATL_BUR_COST, " _
& "ACT_ATL_SER_COST, EST_TTL_MAT_COST, EST_TTL_LAB_COST, EST_TTL_BUR_COST, EST_TTL_SER_COST, REM_TTL_MAT_COST, REM_TTL_LAB_COST, REM_TTL_BUR_COST, REM_TTL_SER_COST, " _
& "ACT_TTL_MAT_COST, ACT_TTL_LAB_COST, ACT_TTL_BUR_COST, ACT_TTL_SER_COST, SPLIT_ADJUSTMENT, MILESTONE_ID, SCHEDULE_TYPE, MIN_SEGMENT_SIZE, PROTECT_COST, DRAWING_FILE, " _
& "DISPATCHED_QTY, SERVICE_MIN_CHG, VENDOR_ID, VENDOR_SERVICE_ID, SERVICE_PART_ID, LAST_DISP_DATE, LAST_RECV_DATE, WAREHOUSE_ID, ALLOCATED_QTY, FULFILLED_QTY, " _
& "LEAST_MIN_MOVE_QTY, MAX_GAP_PREV_OP, APPLY_CALENDAR, MAX_DOWNTIME, ACCUM_DOWNTIME, RUN_QTY_PER_CYCLE, USER_1, USER_2, USER_3, USER_4, USER_5, USER_6, USER_7, USER_8, " _
& "USER_9, USER_10, UDF_LAYOUT_ID, NUM_MEM_TO_SCHED, SERVICE_BUFFER, MILESTONE_SUB_ID, POST_MILESTONE, PROJ_MILESTONE_OP, WBS_CODE, WBS_START_DATE, WBS_END_DATE, " _
& "WBS_DURATION, MILESTONE_SEQ_NO, PRD_INSP_PLAN_ID, SETUP_INSPECT_REQ, RUN_INSPECT_REQ, STATUS_EFF_DATE, PRED_SUB_ID, PRED_SEQ_NO, SITE_ID, SCHED_CAPACITY_USAGE)" _
& "SELECT WORKORDER_TYPE, WORKORDER_BASE_ID + 'F', WORKORDER_LOT_ID, WORKORDER_SPLIT_ID, WORKORDER_SUB_ID, SEQUENCE_NO, RESOURCE_ID, SETUP_HRS, " _
& "RUN, RUN_TYPE, LOAD_SIZE_QTY, RUN_HRS, MOVE_HRS, TRANSIT_DAYS, SERVICE_ID, SCRAP_YIELD_PCT, SCRAP_YIELD_TYPE, FIXED_SCRAP_UNITS, MINIMUM_MOVE_QTY, CALC_START_QTY, " _
& "CALC_END_QTY, COMPLETED_QTY, DEVIATED_QTY, ACT_SETUP_HRS, ACT_RUN_HRS, 'R', SETUP_COMPLETED, SERVICE_BEGIN_DATE, NULL, OPERATION_TYPE, DRAWING_ID, DRAWING_REV_NO, " _
& "OVERRIDE_QTYS, BEGIN_TRACEABILITY, CAPACITY_USAGE_MAX, CAPACITY_USAGE_MIN, TEST_ID, SPC_QTY, NULL, NULL, NULL, ISDETERMINANT, " _
& "SETUP_COST_PER_HR, RUN_COST_PER_HR, RUN_COST_PER_UNIT, BUR_PER_HR_SETUP, BUR_PER_HR_RUN, BUR_PER_UNIT_RUN, SERVICE_BASE_CHG, BUR_PERCENT_SETUP, BUR_PERCENT_RUN, " _
& "BUR_PER_OPERATION, EST_ATL_LAB_COST, EST_ATL_BUR_COST, EST_ATL_SER_COST, REM_ATL_LAB_COST, REM_ATL_BUR_COST, REM_ATL_SER_COST, ACT_ATL_LAB_COST, ACT_ATL_BUR_COST, " _
& "ACT_ATL_SER_COST, EST_TTL_MAT_COST, EST_TTL_LAB_COST, EST_TTL_BUR_COST, EST_TTL_SER_COST, REM_TTL_MAT_COST, REM_TTL_LAB_COST, REM_TTL_BUR_COST, REM_TTL_SER_COST, " _
& "ACT_TTL_MAT_COST, ACT_TTL_LAB_COST, ACT_TTL_BUR_COST, ACT_TTL_SER_COST, SPLIT_ADJUSTMENT, MILESTONE_ID, SCHEDULE_TYPE, MIN_SEGMENT_SIZE, PROTECT_COST, DRAWING_FILE, " _
& "DISPATCHED_QTY, SERVICE_MIN_CHG, VENDOR_ID, VENDOR_SERVICE_ID, SERVICE_PART_ID, LAST_DISP_DATE, LAST_RECV_DATE, WAREHOUSE_ID, ALLOCATED_QTY, FULFILLED_QTY, " _
& "LEAST_MIN_MOVE_QTY, MAX_GAP_PREV_OP, APPLY_CALENDAR, MAX_DOWNTIME, ACCUM_DOWNTIME, RUN_QTY_PER_CYCLE, USER_1, USER_2, USER_3, USER_4, USER_5, USER_6, USER_7, USER_8, " _
& "USER_9, USER_10, UDF_LAYOUT_ID, NUM_MEM_TO_SCHED, SERVICE_BUFFER, MILESTONE_SUB_ID, POST_MILESTONE, PROJ_MILESTONE_OP, WBS_CODE, WBS_START_DATE, WBS_END_DATE, " _
& "WBS_DURATION, MILESTONE_SEQ_NO, PRD_INSP_PLAN_ID, SETUP_INSPECT_REQ, RUN_INSPECT_REQ, STATUS_EFF_DATE, PRED_SUB_ID, PRED_SEQ_NO, SITE_ID, SCHED_CAPACITY_USAGE" _
& "FROM MBUK.dbo.OPERATION db2 " _
& "WHERE (db2.WORKORDER_BASE_ID = '" & rw.Cells(8).Value & "')")
CMDoperation.ExecuteNonQuery()
The error I get is {"Incorrect syntax near '.'."}
The SQL command is simply inserting data from a table in database A into a table in database B... Nothing complex.
Can anyone spot where I'm going wrong here?
Thanks
Here my 2 cents:
pay attention to VB concatenation, the end of the line is strictly attached to the following one, so in your code
& "WBS_DURATION, MILESTONE_SEQ_NO, PRD_INSP_PLAN_ID, SETUP_INSPECT_REQ, RUN_INSPECT_REQ, STATUS_EFF_DATE, PRED_SUB_ID, PRED_SEQ_NO, SITE_ID, SCHED_CAPACITY_USAGE" _
& "FROM MBUK.dbo.OPERATION db2 " _
vb ends concatenating words in this way: SCHED_CAPACITY_USAGEFROM
so add an extra space at the end of each line you concatenate.

Executing Multiple SQL statements in a single command against SQLServer Database in vb6

I am trying to execute multiple SQL statements against a SQL server database using ADODB and vb6.
when I open a recordset the code stops with the following error code:
Run-time error '3704':
Operation is not allowed when object is closed.
here is my code:
Dim sql As String
sql = "WITH " & vbCrLf & _
"q AS" & vbCrLf & _
"(SELECT Item_No, Unit_OldQuantity" & vbCrLf & _
"FROM dbo.The_Units), sequenced AS" & vbCrLf & _
"(SELECT ROW_NUMBER() OVER (PARTITION BY Item_No ORDER BY Unit_OldQuantity DESC) AS sequence_id,*" & vbCrLf & _
"From q)" & vbCrLf & _
"SELECT Item_No , Unit_OldQuantity" & vbCrLf & _
"into #tmpTable" & vbCrLf & _
"From sequenced" & vbCrLf & _
"Where sequence_id = 1" & vbCrLf & _
"SELECT sum(The_ItemDetails.Item_Cost / #tmpTable.Unit_OldQuantity * The_ItemDetails.Item_Quantity) AS Total" & vbCrLf & _
"FROM The_Items INNER JOIN The_ItemDetails ON The_Items.Item_No = The_ItemDetails.Item_No INNER JOIN #tmpTable ON The_ItemDetails.Item_No = #tmpTable.Item_No" & vbCrLf & _
"Where the_items.Item_kind = 0"
Dim connText As String
connText = "Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=AlmohasebSQL;Data Source=server-pc\SQLEXPRESS"
Db_Almohaseb.ConnectionString = connText
Db_Almohaseb.Open
Dim RS_ItemDetails As New ADODB.Recordset
RS_ItemDetails.Open sql, Db_Almohaseb, adOpenStatic, adLockOptimistic, adCmdText
Text1.Text = RS_ItemDetails.RecordCount
I can run any other sql statement using the same connection but not this one.
I can also run this command in .net but not in vb6.
Right now I just need to know why this is happening, and I am feeling woozy from banging my head against the desk.
please can someone shed some light on this.
Thanks
When you have a sql statement with multiple sql statements, you need to use SET NOCOUNT ON, like this:
sql = "SET NOCOUNT ON;" & _
"WITH " & vbCrLf & _
"q AS" & vbCrLf & _
"(SELECT Item_No, Unit_OldQuantity" & vbCrLf & _
"FROM dbo.The_Units), sequenced AS" & vbCrLf & _
"(SELECT ROW_NUMBER() OVER (PARTITION BY Item_No ORDER BY Unit_OldQuantity DESC) AS sequence_id,*" & vbCrLf & _
"From q)" & vbCrLf & _
"SELECT Item_No , Unit_OldQuantity" & vbCrLf & _
"into #tmpTable" & vbCrLf & _
"From sequenced" & vbCrLf & _
"Where sequence_id = 1" & vbCrLf & _
"SELECT sum(The_ItemDetails.Item_Cost / #tmpTable.Unit_OldQuantity * The_ItemDetails.Item_Quantity) AS Total" & vbCrLf & _
"FROM The_Items INNER JOIN The_ItemDetails ON The_Items.Item_No = The_ItemDetails.Item_No INNER JOIN #tmpTable ON The_ItemDetails.Item_No = #tmpTable.Item_No" & vbCrLf & _
"Where the_items.Item_kind = 0"
Remove the "#" :
#tmpTable.Unit_OldQuantity
should be
tmpTable.Unit_OldQuantity
The only available solution to my problem is to move the statements to a stored procedure.
So I check if the procedure exists in the targeted db, if not I will create the procedure; else, I execute the procedure with the proper parameters.
I have also included the logic for checking the temp file if it exists in the db.

How to write a SQL command to move all old data from access table into another database/table?

I have a table in MS Access 2003 in which I want to archive all old data.
The criteria is that the creation data should be less than a specific date.
I can write a SQL statement to select them, but I don't know how to move them to another database/table? Assuming that the archive database/table is already created and data structure matches current table.
Also how I can make sure that all data which is moved to archive table is removed from current table?
I want to write VBA code to run the command check that data is archived correctly.
You want to 1) move data meeting certain criteria from one table to another, existing table with the same format. 2) You want to "make sure that all data which is moved to archive table is removed from current table." And 3) you "want to write VBA code to run the command check that data is archived correctly."
Contrary to popular opinion, Access does support transactions (the claim that Access SQL does not support transactions is true, but we can still use transactions in VBA code). So modifying code in this post to use transactions in a workspace, I believe this would do the trick (tested in Access 2010 using DAO).
The code to lock, get counts and unlock is not really necessary, and may increase the difficulty of implementing the archive, since it will require that no one be writing to the table while you're updating it. And if it did find a problem, Access does not support transaction logging, so you would have a very short list of options as to how to fix it. But it sounded like you wanted to be absolutely sure the counts were correct, so this adds another level, arguably unnecessary, of checking.
Option Compare Database
Option Explicit
Sub ArchiveOldRecords()
Dim nSourceCount As Long, nMoveCount As Long, nDestCount As Long
Dim strSQL As String, sMsg As String
Dim rsLock As DAO.Recordset
Dim rsBefore As DAO.Recordset, rsAfter As DAO.Recordset
Dim wrk As Workspace, db As DAO.Database
Const strcTableSource As String = "t_TestWithDate" ' Move records FROM table
Const strcTableArch As String = "t_ArchiveTestWithDate" ' Move records TO table
Const strcWHERE As String = " WHERE field2 < " _
& "DATEADD(""yyyy"", -1, Date())" ' Select date field and DATEADD params
Const strcCount As String = "SELECT COUNT(*) As "
On Error GoTo TrapError
Set db = CurrentDb
Set wrk = DBEngine.Workspaces(0)
' Lock table - so no one can add/delete records until count is verified
Set rsLock = db.OpenRecordset(strcTableSource, dbOpenTable, dbDenyWrite)
' Get initial table counts
Set rsBefore = db.OpenRecordset( _
strcCount & "SourceCount, " _
& "(SELECT COUNT(*) FROM " & strcTableSource _
& strcWHERE & ") As MoveCount, " _
& "(SELECT COUNT(*) FROM " & strcTableArch & ") As DestCount " _
& "FROM " & strcTableSource & ";", dbOpenForwardOnly)
nSourceCount = rsBefore!SourceCount
nMoveCount = rsBefore!MoveCount
nDestCount = rsBefore!DestCount
rsBefore.Close
wrk.BeginTrans
' Copy records
strSQL = "INSERT INTO " & strcTableArch _
& " SELECT * FROM " & strcTableSource & " " & strcWHERE & ";"
db.Execute strSQL, dbFailOnError
' Unlock table - only needed for counts
rsLock.Close
Set rsLock = Nothing
' Delete copied records
strSQL = "DELETE * FROM " & strcTableSource & " " & strcWHERE & ";"
db.Execute strSQL, dbDenyWrite + dbFailOnError
' Lock table - only needed for counts
Set rsLock = db.OpenRecordset(strcTableSource, dbOpenTable, dbDenyWrite)
wrk.CommitTrans
' Get final table counts
Set rsAfter = db.OpenRecordset( _
strcCount & "SourceCount, " _
& "(SELECT COUNT(*) FROM " & strcTableSource _
& strcWHERE & ") As MoveCount, " _
& "(SELECT COUNT(*) FROM " & strcTableArch & ") As DestCount " _
& "FROM " & strcTableSource & ";", dbOpenForwardOnly)
' Double-check counts
If (rsAfter!SourceCount <> nSourceCount - nMoveCount) _
Or (rsAfter!DestCount <> nDestCount + nMoveCount) _
Or (rsAfter!MoveCount > 0) Then
sMsg = vbNewLine
sMsg = sMsg & "Records in " & strcTableSource & " before: "
sMsg = sMsg & nSourceCount
sMsg = sMsg & vbTab & "after: "
sMsg = sMsg & rsAfter!SourceCount
sMsg = sMsg & vbNewLine
sMsg = sMsg & "Records to archive from " & strcTableSource & ": "
sMsg = sMsg & nMoveCount
sMsg = sMsg & vbTab & "after: "
sMsg = sMsg & rsAfter!MoveCount
sMsg = sMsg & vbNewLine
sMsg = sMsg & "Records in " & strcTableArch & " before: "
sMsg = sMsg & nDestCount
sMsg = sMsg & vbTab & "after: "
sMsg = sMsg & rsAfter!DestCount
MsgBox "Count double-check failed" & sMsg
End If
Exit_Sub:
On Error Resume Next
' Unlock table and close recordsets
rsLock.Close
rsBefore.Close
rsAfter.Close
Set rsBefore = Nothing
Set rsAfter = Nothing
Set rsLock = Nothing
Set db = Nothing
Set wrk = Nothing
Exit Sub
TrapError:
MsgBox "Failed: " & Err.Description
wrk.Rollback
Err.Clear
Resume Exit_Sub
End Sub
There is no MOVE command but you can copy the records across to the target and then use a similar query to remove them from the source when you are sure you have no Paste Errors.
INSERT INTO MyArchive (fld1, fld2, fld3, fld4) SELECT fld1, fld2, fld3, fld4 FROM MyTable WHERE fld4 < DATEADD("y", -5, Date())
That copies across everything older than 5 years. After confirming the transfer,
DELETE * FROM MyTable WHERE fld4 < DATEADD("y", -5, Date())
That's off the top of my head and I transition between T-SQL and MS Access a fair bit but I think that is pretty solid Access query code. Your own field lists will vary accordingly.

Insert into SQL - records gets written twice

I have a program that is Access 2010 front end and a SQL Server database as back end.
I wrote a routine that inserts a record into SQL Server.
Here is the code:
DoCmd.RunSQL "INSERT INTO [dbo_phoneno] (dtstamp, who, what, sortorder, company, typephoneno, name, wphone, cphone, mob) " _
& "VALUES(" _
& "'" & pubDTStamp & "'," _
& "'" & pubWho & "'," _
& "'" & pubWhat & "'," _
& "'" & pubSortOrder & "'," _
& "'" & pubCompany & "'," _
& "'" & pubType & "'," _
& "'" & pubName & "'," _
& "'" & pubWphone & "'," _
& "'" & pubCphone & "'," _
& "'" & pubMob & "') "
The code works fine except when I exit out of the program the record is written out again. I checked the code but do not see where it can be. Does anyone have suggestions?
Either your code gets executed twice or you have a trigger somewhere that does the additional INSERT.
Use Sql Profiler and run a trace. You'll be able to find from where the second INSERT comes from. If it's not from a trigger, then you'll have to set a breakpoint in your app and run it in debug mode.

Updating to a linked SQL Table

I have a form which writes data to a linked SQL table, and one of the functions is an EDIT function, but when I make the edits and resubmit the data I get the error
Run Time Error 3073 Operation Must Use an Updateable Query
I have used this code before on normal Access tables housed in the database where the form is and it works fine, do I need to make some alterations to the code since it is editing the data on a linked SQL table? The code is as follows?
CurrentDb.Execute "UPDATE dbo_AC_CD_Data_Form " & _
"SET EmployeeID='" & Me.txtEmpID & "'" & _
", EmployeeName='" & Me.txtEmpName & "'" & _
", Gender='" & Me.cboGender & "'" & _
", EEOC='" & Me.cboEEOC & "'" & _
", ReadinessLevel='" & Me.cboReadyLvl & "'" & _
", Division='" & Me.cboDivision & "'" & _
", Center='" & Me.txtCenter & "'" & _
", EmployeeFeedback='" & Me.txtFeedback & "'" & _
", DevelopmentForEmployee='" & Me.txtDevelopment & "'" & _
", Justification='" & Me.txtJustification & "'" & _
", Changed ='" & Me.cboChanged & "'" & _
" WHERE EmployeeID='" & Me.txtEmpID & "'"
Delete the linked table in Access and link it again. The wizard should ask to you for a primary key. Select the field or fields that compound the primary key.
Note that is not necessary that the original table have a pk (This is usually happen linking views).

Resources