I have a VBA script that is inserting and updating records in a SQL Server database table. However, the update part of the script is hanging.
The script first inserts 18 records into a table using an INSERT query. Then, it loops through each of those 18 records to update 2 fields in each record using an UPDATE query. The update query is fairly simple and when I run it directly in SQL Server it runs immediately. However, that same UPDATE query will not finish when executed in VBA.
The sweet spot seems to be 16 records. If I only include 16 of the 18 records in the original insert, the update query works fine. As soon as I increase it to 17 records, it doesn't.
Sample script below.
Sub ExecuteMyScript()
'Declare local variables.
Dim vCNSHARE As ADODB.Connection
Dim vCMINSERT As ADODB.Command, vCMLOOP As ADODB.Command, vCMUPDATE As ADODB.Command
Dim vRSINSERT As ADODB.Recordset, vRSLOOP As ADODB.Recordset, vRSUPDATE As ADODB.Recordset
Dim vREFERENCEID As String
'Open main connection.
Set vCNSHARE = New ADODB.Connection
vCNSHARE.ConnectionTimeout = 3600
vCNSHARE.Open "my_sqlserver_connection_string"
'Set the command and record objects and apply the to the shared connection.
'Set Insert objects. Used to insert the records.
Set vCMINSERT = New ADODB.Command
vCMINSERT.ActiveConnection = vCNSHARE
vCMINSERT.CommandType = adCmdText
Set vRSINSERT = New ADODB.Recordset
'Set Loop objects. Used to loop through the records inserted.
Set vCMLOOP = New ADODB.Command
vCMLOOP.ActiveConnection = vCNSHARE
vCMLOOP.CommandType = adCmdText
Set vRSLOOP = New ADODB.Recordset
'Set Update objects. Used to update the records inserted.
Set vCMUPDATE = New ADODB.Command
vCMUPDATE.ActiveConnection = vCNSHARE
vCMUPDATE.CommandType = adCmdText
Set vRSUPDATE = New ADODB.Recordset
'Run process.
'Insert the records.
'The full INSERT query is not shown, but it inserts 18 records based on a JSON.
'The JSON has a reference ID that is used in the UPDATE query to find the relevant record inserted.
vCMINSERT.CommandText = "INSERT INTO [MYTABLE] (blah, MYTABLE_REFERNCEID) SELECT blah, MYTABLE_REFERNCEID"
Set vRSINSERT = vCMINSERT.Execute()
'Loop through the records inserted.
vCMLOOP.CommandText = "SELECT * FROM [MYTABLE] WHERE MYTABLE_ID = {it_finds_the_record_added}"
Set vRSLOOP = vCMLOOP.Execute()
Do Until vRSLOOP.EOF
'Retrieve the reference to use it in the UPDATE query.
vREFERENCEID = vRSLOOP("MYTABLE_REFERNCEID").Value
'Update the recrods. This hangs when the EXECUTE is run.
vCMUPDATE.CommandText = MyUpdateScript(MyReference:=vREFERENCEID)
Set vRSUPDATE = vCMUPDATE.Execute()
'Move to the next record that was inserted.
vRSLOOP.MoveNext
Loop
'All done.
'Close connnection and clear objects.
vCNSHARE.Close
Set vCMINSERT = Nothing
Set vCMLOOP = Nothing
Set vCMUPDATE = Nothing
Set vRSINSERT = Nothing
Set vRSLOOP = Nothing
Set vRSUPDATE = Nothing
End Sub
Function MyUpdateScript(MyReference As String) As String
Dim vSCRIPT As String
vSCRIPT = ""
vSCRIPT = vSCRIPT & "DECLARE #JSON AS nvarchar(max);
vSCRIPT = vSCRIPT & "SET #JSON = N'[
vSCRIPT = vSCRIPT & " {
vSCRIPT = vSCRIPT & " ""label"": ""simplejson"", "
vSCRIPT = vSCRIPT & " ""fields"": [ "
vSCRIPT = vSCRIPT & " {
vSCRIPT = vSCRIPT & " ""field1"": ""Some Value 1"", "
vSCRIPT = vSCRIPT & " ""field2"": ""Some Value 2"" "
vSCRIPT = vSCRIPT & " } "
vSCRIPT = vSCRIPT & " ] "
vSCRIPT = vSCRIPT & " } "
vSCRIPT = vSCRIPT & "]'; "
vSCRIPT = vSCRIPT & "UPDATE "
vSCRIPT = vSCRIPT & " [MYTABLE] "
vSCRIPT = vSCRIPT & "SET "
vSCRIPT = vSCRIPT & " [MYTABLE_FIELD1]=T0.[MYTABLE_FIELD1], "
vSCRIPT = vSCRIPT & " [MYTABLE_FIELD2]=T0.[MYTABLE_FIELD2] "
vSCRIPT = vSCRIPT & "FROM ( "
vSCRIPT = vSCRIPT & " SELECT "
vSCRIPT = vSCRIPT & " [MYTABLE_FIELD1], "
vSCRIPT = vSCRIPT & " [MYTABLE_FIELD2] "
vSCRIPT = vSCRIPT & " FROM "
vSCRIPT = vSCRIPT & " OPENJSON (#JSON) WITH ( "
vSCRIPT = vSCRIPT & " MYTABLE_DETAILFIELDS nvarchar(max) '$.fields' AS JSON "
vSCRIPT = vSCRIPT & " ) AS T1 "
vSCRIPT = vSCRIPT & " CROSS APPLY "
vSCRIPT = vSCRIPT & " OPENJSON (T1.MYTABLE_DETAILFIELDS) WITH ( "
vSCRIPT = vSCRIPT & " MYTABLE_FIELD1 nvarchar(300) '$.field1', "
vSCRIPT = vSCRIPT & " MYTABLE_FIELD2 nvarchar(300) '$.field2' "
vSCRIPT = vSCRIPT & " ) AS T2 "
vSCRIPT = vSCRIPT & ") AS T0"
vSCRIPT = vSCRIPT & "WHERE "
vSCRIPT = vSCRIPT & " [MYTABLE_REFERNCEID] = '" & MyReference & "'"
MyUpdateScript = vSTRING
End Function
EDIT:
As suggested, changed "vRSLOOP" to "vRSUPDATE" and the code still hangs
'Set Update objects. Used to update the records inserted.
Set vCMUPDATE = New ADODB.Command
vCMUPDATE.ActiveConnection = vCNSHARE
vCMUPDATE.CommandType = adCmdText
Set vRSLOOP = New ADODB.Recordset
Set the intended recordset:
'Set Update objects. Used to update the records inserted.
Set vCMUPDATE = New ADODB.Command
vCMUPDATE.ActiveConnection = vCNSHARE
vCMUPDATE.CommandType = adCmdText
Set vRSUPDATE = New ADODB.Recordset
Related
I am using SQL update query in VBA and I am getting the datatype mismatch error. I know that error is basically because of the column spare part. The spare part column contains numeric and alphanumeric values.
Public Function UpdateDistinctColumnFRNumberBasis()
StrInvoiceNumber = "109839-01"
FRSparepartNumber = "FT7119907459"
MergedInvoiceFile = "/test.xlsx"
Dim objConn As Object
Dim objRecordSet As Object
Set objConn = CreateObject("ADODB.Connection")
Set objRecCmd = CreateObject("ADODB.Command")
Set objRecCmd_Update = CreateObject("ADODB.Command")
objConn.Open ("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & _
MergedInvoiceFile & ";Extended Properties=""Excel 8.0;""")
strSQL = " Update [Tabelle1$] SET [Status] = 'Include' Where " & _
"([RECHNR] ='" & StrInvoiceNumber & "' AND [Sparepart] = " & FRSparepartNumber & ")"
objConn.Execute strSQL
objConn.Close
End Function
As commented, the partnumber is text, thus it must be quoted in the SQL:
FRSparepartNumber = "FT7119907459"
' snip
strSQL = "Update [Tabelle1$] SET [Status] = 'Include' Where " & _
"([RECHNR] = '" & StrInvoiceNumber & "' AND " & _
"[Sparepart] = '" & FRSparepartNumber & "')"
I tested an UPDATE query in Access's query design, and it works, but when I try to use it in my module, I get the error:
Invalid SQL statement; expected... or 'UPDATE'.
My query:
strSql = "UPDATE " & rs.Fields("tableName") & _
" SET " & rs.Fields("foreignKeyName") & " = " & rsContacts.Fields("contactId") & _
" WHERE contactId = " & ContactID
rs: a table that has tableName, foriegnKeyName of the tables to update
rsContacts: a list of contactIds (currently standing on a particular one).
The actual string comes out like this:
UPDATE myTable SET ContactId = 5 WHERE contactId = 2
If the query works, and it is an action query, why am I getting this error?
This is my full code:
Public Sub updateChildTables(ByVal ContactID As Long, ByVal CompanyID As Long)
Dim strSql As String
Dim rs As Recordset
Dim rsPending As Recordset
strSql = "SELECT contactID FROM contacts _
WHERE companyId = " & CompanyID & " and contactId <> " & ContactID
Set rs = CurrentDb.OpenRecordset(strSql)
If Not (rs.BOF And rs.EOF) Then
rs.MoveFirst
strSql = "SELECT * FROM childTables"
Set rsChild = CurrentDb.OpenRecordset(strSql)
rsChild.MoveFirst
Do While Not rsChild.EOF
strSql = "UPDATE " & rsChild.Fields("tableName") & " SET " & rsChild.Fields("foreignKeyName") & " = " & rs.Fields("contactId") & " WHERE contactId = " & ContactID
DoCmd.RunSQL strSql
rs.moveNext
Loop
rsChild.Close
Set rsChild = Nothing
End If
Here is my idea for debugging and possibly even resolving this.
Create a query from within Access normally -- name it UpdateMyTable, for the sake of this example.
Then, rather than using the DoCmd, actually execute this specific query from your VBA.
Dim qry As QueryDef
strSql = "UPDATE " & rsChild.Fields("tableName") & " SET " & _
rsChild.Fields("foreignKeyName") & " = " & _
rs.Fields("contactId") & " WHERE contactId = " & ContactID
Set qry = CurrentDb.QueryDefs("UpdateMyTable")
qry.SQL = strSql
qry.Execute
The big advantage of this is that you can very easily debug this from within Access to both see the rendered SQL and manually run it / tweak it.
I am querying Active Directory to list Users and other fields in Access. Is there a way to append my queried results into an existing table? Currently I am trying to use INSERT INTO but having issues with my Object variable not being set or block variable.
Private Sub Command0_Click()
Dim objRecordSet As Object
Dim objCommand As Object
Dim objConnection As Object
Dim dbs As Database
Const ADS_SCOPE_SUBTREE = 2
Set objConnection = CreateObject("ADODB.Connection")
Set objCommand = CreateObject("ADODB.Command")
objConnection.Provider = "ADsDSOObject"
objConnection.Open "Active Directory Provider"
Set objCommand.ActiveConnection = objConnection
objCommand.Properties("Page Size") = 1000
objCommand.Properties("Searchscope") = ADS_SCOPE_SUBTREE
objCommand.Properties("Sort On") = "whenCreated"
objCommand.CommandText = _
"SELECT Name,Title,PhysicalDeliveryOfficeName,WhenCreated,Mail FROM 'LDAP://OU=Standard Users,OU=Active Users,OU=All Users,DC=contoso,dc=local' WHERE objectCategory='user'"
Set objRecordSet = objCommand.Execute
objRecordSet.MoveFirst
Do Until objRecordSet.EOF
dbs.Execute " INSERT INTO ADUsers" & "(Name,Title,Site,Created,Email) VALUES " & "(objRecordSet.Fields('Name').Value,objRecordSet.Fields('Title').Value,objRecordSet.Fields('physicalDeliveryOfficeName').Value,objRecordSet.Fields('whenCreated').Value,objRecordSet.Fields('Mail').Value);"
dbs.Close
Debug.Print objRecordSet.Fields("Name").Value; "," & objRecordSet.Fields("Title").Value; "," & objRecordSet.Fields("physicalDeliveryOfficeName").Value; "," & objRecordSet.Fields("whenCreated").Value; "," & objRecordSet.Fields("Mail").Value
objRecordSet.MoveNext
Loop
End Sub
Everything inside doublequotes " is interpreted as string not as code and strings (the values of objRecordSet.Fields("myFieldName").Value) have to be quoted in insert statement.
dim strSQLInsert as String
strSQLInsert = "INSERT INTO ADUsers(Name,Title,Site,Created,Email) VALUES ('" & _
objRecordSet.Fields("Name").Value & "','" & _
objRecordSet.Fields("Title").Value & "','" &
objRecordSet.Fields("physicalDeliveryOfficeName").Value & "','" & _
objRecordSet.Fields("whenCreated").Value & "','" & _
objRecordSet.Fields("Mail").Value & "');"
Debug.Print strSQLInsert
dbs.Execute strSQLInsert
Store your sql statements in a string, then you can check it with Debug.Print.
Consider a parameterized query using querydefs to avoid the need of quotes. Also be sure to initialize the database object which may be your main issue: set dbs = CurrentDb.
...
Dim strSQL As String
Set dbs = CurrentDb
strSQL = "PARAMETERS NameParm TEXT(255), TitleParam TEXT(255), SiteParam TEXT(255)," _
& " CreatedParm Date, EmailParam TEXT(255);" _
& " INSERT INTO ADUsers (Name, Title, Site, Created, Email)" _
& " VALUES ([NameParm], [TitleParam], [SiteParam], [Created], [Email]);"
Do Until objRecordSet.EOF
Set qdef = dbs.CreateQueryDef("", strSQL)
qdef!NameParam = objRecordSet![Name]
qdef!TitleParam = objRecordSet![Title]
qdef!SiteParam = objRecordSet![PhysicalDeliveryOfficeName]
qdef!CreatedParam = objRecordSet![WhenCreated]
qdef!EmailParam = objRecordSet![Mail]
qdef.Execute (dbfailOnError)
Set qdef = Nothing
objRecordSet.MoveNext
Loop
I'm getting an error saying that Access cannot find the referenced form CFRRR but there is definitely a form there. Not sure if I'm just not writing the code correctly.
Public Function AssignNullProjects() As Long
Dim db As dao.Database
Dim rs As dao.Recordset
Dim strSQL As String
Set db = CurrentDb
strSQL = "SELECT CFRRRID, [program], [language] FROM CFRRR WHERE assignedto Is Null"
Set rs = db.OpenRecordset(strSQL, dbOpenDynaset)
If Not rs.BOF And Not rs.EOF Then
While Not rs.EOF
strSQL = "UPDATE CFRRR SET assignedto = " & GetNextAssignee & ", assignedby = " & [Forms]![CFRRR]![assignedby] & ", Dateassigned = #" & Now & "#, actiondate = #" & Now & "#, Workername = " & _ [Forms]![CFRRR]![assignedto] & ", WorkerID = " & [Forms]![CFRRR]![assignedto] & " WHERE CFRRRID = " & rs!CFRRRID
db.Execute strSQL, dbFailOnError
rs.MoveNext
Wend
End If
rs.Close
db.Close
Set rs = Nothing
Set db = Nothing
End Function
Public Function GetNextAssignee(program As String, Language As String) As Long
' Returns UserID as a Long Integer with the lowest [TS] value,
' and updates same [TS] by incremented with 1.
Dim db As dao.Database
Dim rs As dao.Recordset
Dim strSQL As String
Set db = CurrentDb
strSQL = "SELECT TOP 1 WorkerID FROM attendance WHERE [Programs] LIKE '*" & program & "*' AND [Language] = '" & Language & "' AND [Status] = '" & Available & "' ORDER BY TS ASC"
Set rs = db.OpenRecordset(strSQL, dbOpenDynaset)
If Not rs.BOF And Not rs.EOF Then
'Found next assignee, update date/time stamp
'strSQL = "UPDATE tblUser SET TS = " & DMax("[TS]", tblUser) + 1 & " WHERE [WorkerID]= " & rs!workerid
strSQL = "UPDATE attendance SET TS = " & DMax("[TS]", "attendance") + 1 & " WHERE [WorkerID]= " & rs!workerid
db.Execute strSQL, dbFailOnError
GetNextAssignee = rs!workerid
Else
'Field TS has NO VALUE FOR ALL RECORDS!
'Code calling this function should check for a return of 0 indicating an error.
GetNextAssignee = 0
End If
rs.Close
db.Close
Set rs = Nothing
Set db = Nothing
End Function
I am trying to update a single record in sql using a recordset I'm Pulling data from one recordset and trying to save it to another table in the database This is the code I have the insert statement runs fine in SQL.
' Opening the connection
cn.ConnectionString = "Provider=SQLOLEDB; Data Source=" & dbLocation & "; Initial Catalog=Posbdat; User Id=sa"
cn.Open
rh.ConnectionString = "Provider=SQLOLEDB; Data Source=" & dbLocation & "; Initial Catalog=Postrans; User Id=sa"
rh.Open
rs.Open "Select Top 1 * from CustomerPoints order by RedemptionDate desc", cn, adModeReadWrite
x.Open " Select Top 1 * from Register_Header order by datetime desc", rh, adModeReadWrite
rt.Open " SELECT top 1 upc FROM Register_Trans INNER JOIN Register_Header ON Register_Trans.trans_no = Register_Header.trans_no Where trans_subtype = 'AP' Order by Register_Trans.datetime desc ", rh, adOpenDynamic
Debug.Print x!emp_no
Debug.Print x!till_no
Debug.Print x.Fields(10)
Debug.Print itemupc
itemupc = rt.Fields(0)
Dim cmd As New ADODB.Recordset
cmd.Open "UPDATE CustomerPoints set emp_no = " & x!emp_no & _
", till_no = " & x!till_no & " purch_amt = " & x!Total & _
", item_redeem = ' " & itemupc & " ' Where RedemptionDate = (Select top 1 * from CustomerPoints order by " & _
"RedemptionDate Desc)", cn, adOpenDynamic
cmd.update
I haven't closed any of the connections or cleaned it up because it won't run without crashing.
It has been a long time but this is how I used to execute update statements:
Dim conTemp As New ADODB.Connection
conTemp.CommandTimeout = mvarconConnection.CommandTimeout
conTemp.ConnectionTimeout = mvarconConnection.ConnectionTimeout
conTemp.CursorLocation = mvarconConnection.CursorLocation
conTemp.Mode = mvarconConnection.Mode
conTemp.ConnectionString = mvarconConnection.ConnectionString
conTemp.Open mvarconConnection.ConnectionString
conTemp.Execute "SET CONCAT_NULL_YIELDS_NULL OFF"
conTemp.Execute "UPDATE CustomerPoints set emp_no = " & x!emp_no & _
", till_no = " & x!till_no & " purch_amt = " & x!Total & _
", item_redeem = ' " & itemupc & " ' Where RedemptionDate = (Select top 1 * from
CustomerPoints order by " & _
"RedemptionDate Desc)"
The mvarconConnection is just an object that stored all of my DB settings, just replace my settings with your own.