Excel VBA Late Bind to Access and SQL Insert - vba

I am having a frustrating issue with late binding to MS Access from Excel VBA to execute a DML statement like Insert or Update. All of the data I use in vba comes from user defined Classes. I can query just fine but writing to the DB gets different errors each time I try a different way to do the same thing. Below are some links to the same/similar issues, however each is slightly out of context and therefore I could not get passed my problem.
Microsoft.ACE.OLEDB.12.0 Current Recordset does not support updating error received when trying to update access
Operation must use an Updateable Query / SQL - VBA
Update an excel sheet using VBA/ADO
Operation must use an updatable query. (Error 3073) Microsoft Access
https://msdn.microsoft.com/en-us/library/bb220954%28v=office.12%29.aspx?f=255&MSPPError=-2147217396
http://www.access-programmers.co.uk/forums/showthread.php?t=225063
My end goal is to simply execute a DML string statement and it has to use late binding. Mainly I get the 3251 error saying my connection is 'Read Only' or a missing ISAM when I add ReadOnly=0 to the connection string. Fyi, getProjectFile just returns a path to a file starting from the parent folder of my project. I am pretty sure I can just use the connDB.Execute so I only need SQL Insert, I don't want to query first because the queries will get fat quick. I also think something might be wrong with the enum params because the ExecuteOptions want bitmasks instead of just a Long and I don't really know how to do that. From most of my research, I kept getting referred to the LockType and/or cursor not being right. For my environment; Windows 8.1 64bit, MS Office 2010 32bit(required). Does anyone see what is wrong here?
Sub ADO_Tester()
Dim strSQL, strFile, strConnection As String
Dim connDB As Object
'late bind to the ADODB library and get a connection object
Set connDB = CreateObject("ADODB.Connection")
'Connect to the DB
strFile = Application.ActiveWorkbook.Path & "\" & "PortfolioDB.accdb"
strConnection = "Provider = Microsoft.ACE.OLEDB.12.0; data source=" & strFile & ";"
connDB.Open strConnection
'insert statement for a test record
strSQL = "INSERT INTO underlying_symbol (symbol) VALUES ('xyz')"
'execute the
connDB.Execute strSQL, , 2, 1 + 128
'clear the object
connDB.Close
Set connDB = Nothing
End Sub
Edit:
Early binding:
connDB.Execute strSQL, , adCmdText + adExecuteNoRecords
Late Binding: How to enter the value for adExecuteNoRecords? On msdn it is 0x80 and another post says &H0001,either way it gives a syntax error. It says enter a bitmask for this enum value.
connDB.Execute strSQL, , 1 + 0x80
Edit: Now the correct way -
adExecuteNoRecords (the ADO enum value) = 0x80 (a binary value) = 128 (a decimal value)
connDB.Execute strSQL, , 1 + 128
Edit: Now the issue gets even deeper. When I execute the code in a test spreadsheet into a test database, it works. When I copy and paste into the actual project spreadsheet and point to actual project db, I get the error: operation must use an updateable query . . . again. Same db name, same dml, same table name. The only difference is the actual DB is a product of a split to separate it from the forms and code in Access. Could this have changed some setting to make it read only?
Edit: It just gets deeper and deeper. The issue causing it not to work in the project db is because I have some Excel Tables querying the db. I made these through the Excel UI, Ribbon -> External Data -> Access -> etc. . . It has now become obvious these are causing me to be unable to insert DML because they are probably set to read only. How can I change the tables connections permissions? Is there another way I could be making these tables so that I can provide the connection? How to get Tables to be friendly with DML in VBA?

This worked for me:
Option Explicit
Private Const acCmdText As Integer = 1
Sub ADO_Tester()
On Error GoTo ErrorHandler
Dim strSQL As String
Dim strFile As String
'Dim adoRecSet As Object
Dim connDB As Object
'late bind to the ADODB library and get a connection object
Set connDB = CreateObject("ADODB.Connection")
'Connect to the DB
strFile = getProjectFile("core", "PortfolioDB.accdb")
connDB.Open connectionString:="Provider = Microsoft.ACE.OLEDB.12.0; data source=" & strFile & ";"
'If State = 1, db connection is okay.
MsgBox "ADO Connection State is " & connDB.State & "."
'SQL to get the whole [underlying_symbol] table
'strSQL = "underlying_symbol" 'if options 2
'strSQL = "SELECT * FROM underlying_symbol" 'if options 1
strSQL = "INSERT INTO underlying_symbol (symbol) VALUES ('xyz')"
'late bind to adodb and get recordset object
'Set adoRecSet = CreateObject("ADODB.Recordset")
'&H0001 = bitmask for aCmdText
connDB.Execute strSQL, , acCmdText
'With adoRecSet
' .Open Source:=strSQL, _
' ActiveConnection:=connDB, _
' CursorType:=1, _
' LockType:=3, _
' Options:=&H1
'.AddNew
'.fields("symbol") = "XYZ"
'.Update
'End With
'------------------
'close the objects
'adoRecSet.Close
connDB.Close
'destroy the variables
'Set adoRecSet = Nothing
Set connDB = Nothing
ExitMe:
Exit Sub
ErrorHandler:
MsgBox Err.Number & ": " & Err.Description
GoTo ExitMe
End Sub
Added some error handling, a constant that defines acCmdText (Why just not add a reference to ADO library? Up to you, though.), and a message box to check the connection state to the database, as I can't test your getProjectFile function. Late binding doesn't seem to be the issue here, I think the key line is:
connDB.Execute strSQL, , 2, &H1
Can really say what's going on here as I've never done it like this (code doesn't even compile), but changing it to
connDB.Execute strSQL, , acCmdText
worked for me.

Related

How to resolve a connection problem when connecting SQL from VBA XLS " ; VBA error message= 'Not able to find ISAM file'

when setting and running ADODB connection to SQL from VBA xls, I got a error message "Not able to find the ISAM file", I writting the following connection in a VBA Module :
"Provider= Microsoft.ACE.OLEDB.12.0
"Data Source=" & PWRQRYFilePath
Im usiging xls 2019 , 32 bits. Referencing to Microsoft ActiveX Data Objects 6.1 Library.,
check any thing but not able to create and open the connection would you please help me.
Im trying to create and open the connection so I can run SQL queries from VBA xls
Following is a simple query i want to run to obtain a join inner from two spread sheets
But Actually the Query is sending me the error message.
What is the content of the variable PWRQRYFilePath?
For the sake of completeness:
If you want to go the long way, or better spoken, if you need the query more times, as you know, you can put the code lines also in a function an pass the path to the file to it.... here its represented by the Workbook-Property ThisWorkbook.Fullname
Dim rs As Object 'or AS ADODB.Recordset for EarlyBinding/IntelliSense
With rs
.Open "SELECT * FROM [worksheetname$] WHERE [column]='value'", _
";Provider=Microsoft.Ace.OLEDB.12.0" & _
";Extended Properties""Excel 12.0 xml""" & _
";Data Source=" & ThisWorkbook.FullName
'*** do your stuff with recordsetresult
.Close
End With
If you need the query just once, you can use a anonym function call as well:
With CreateObject("ADODB.Recordset")
.OPEN ...
'*** do your stuff ...
.CLOSE
End With

Insert Query/Select Query works in access, but not in vba

I have created a query that works great with no errors in Access, and while trying to translate this to my vba setup I can't figure out why I am not getting any values, even though the query clearly works in access, and causes no errors on the VBA side.
Pulling my hair out here, I have created a side table to see if I could "pseudo-insert" the calculated value, but I get the same issue as above - insert works with no errors in access, goes through in vba with no issues, but doesn't actually insert any data.
I have copied the string queries while pausing code to make sure EVERYTHING matches up between the Access query that works and the VBA query, and haven't found any differences.
I read somewhere since I am trying to pull a "first line" data piece that there may be some HDR setting that I could change, but when I tried to apply any fixes I found they opened another instance of excel and opened a dialogue box.
Please let me know what I am doing wrong here.
Public Function PullNextLineItemNumB(QuoteNum) As Integer
Dim strQuery As String
Dim ConnDB As New ADODB.Connection
Dim myRecordset As ADODB.Recordset
Dim QuoteModifiedNum As String
ConnDB.Open ConnectionString:="Provider = Microsoft.ACE.OLEDB.12.0; data
source=" & ThisWorkbook.Path & "\OEE Info.accdb"
'Query to try and make Access dump the value "18" into the table so I can
grab it after the query is finished, sidestepping excel not working
strQuery = "INSERT INTO TempTableColm (TempColm) SELECT
MAX(MID([Quote_Number_Line],InStr(1,[Quote_Number_Line]," & Chr(34) & "-"
& Chr(34) & ")+1)) AS MaxNum from UnifiedQuoteLog where Quote_Number_Line
like '" & QuoteNum & "*'"
ConnDB.Execute strQuery
'Original query, returns "18" as expected in Access, and null or empty in
the recordset
strQuery = "SELECT MAX(MID([Quote_Number_Line],InStr(1,
[Quote_Number_Line]," & Chr(34) & "-" & Chr(34) & ")+1)) from
UnifiedQuoteLog where Quote_Number_Line like '" & QuoteNum & "*'"
Set myRecordset = ConnDB.Execute(strQuery)
Do Until myRecordset.EOF
For Each fld In myRecordset.Fields
Debug.Print fld.Name & "=" & fld.Value
Next fld
myRecordset.MoveNext
Loop
myRecordset.Close
Set myRecordset = Nothing
ConnDB.Close
Set ConnDB = Nothing
End Function
Actual output from access is "18" which is expected, output from excel's vba recordset is always null or empty string.
It appears I solved the problem, while looking into this apparently the excel operator using ADODB with access is % for LIKE and NOT * (because reasons). As soon as I made that change everything started working.
Can someone explain why that is a thing? I really want to understand why this was a design choice.

Type Mismatch in VBA SQL expression

I've been out of Access for years, but I've been tasked with a small database function. What I need to do is create a query based on dropdown results, and open that query so that end users can copy/paste what they want from it (or the entire result set).
My code looks like this:
Private Sub btnSubmit_Click()
Dim X As String
Dim Y As String
Dim sSQL As String
Dim MyRs As Recordset
If IsNull(cboReportName.Value) Or IsNull(cboError.Value) Or cboReportName.Value = "" Or cboError.Value = "" Then
MsgBox "One or more of your selections is empty."
Exit Sub
End If
X = cboReportName.Column(2)
Y = cboError.Column(1)
sSQL = "Select * from " & X & " where Error = '" & Y & "'"
Set MyRs = CurrentDb.OpenRecordset(sSQL)
End Sub
I'm getting an error on the Set MyRS line, it's telling me there's a Type Mismatch. Does this have to do with how Access uses Short Text and Long Text? There are NULL results in the query, would that throw this off? Any ideas are appreciated.
It is very unlikely that you get a VBA Type Mismatch error from your query since even if the [Error] column were not Text, it would simply return false when comparing to a string value. (This isn't to discount Erik's comment about multiple query levels causing errors... been there, dealt with that, and I believe this could still be a cause if my answer doesn't help.)
It is more likely that you have referenced an ADO library (from VBA window menu Tools | References...) and placed its priority above the default Access data object libraries. That would cause Dim MyRs As Recordset to interpret this as an ADO recordset, but CurrentDb.OpenRecordset(sSQL) will return a DAO.Recordset.
Update the declaration to
Dim MyRs As DAO.Recordset
or change the priority order of the ADO library in the Tools | References... list.

Operation invalid when trying to open Recordset from SQL linked Table

I am trying to open to a recordset of a linked table but i keep getting invalid operation error. it works fine with local table.
I have tried to remove dbOpenTable but the error changed to 'Operation is not supported for this type of object'
It is important to note that i have a very shallow knowledge of vba access.
I would really appreciate any help I can get from this forum
Dim db As DAO. Database
Dim rst As Recordset
Set db=CurrentDb
Set rst = db.OpenRecordset("myTable",dbOpenTable)
rst.Index = "PRODUCT_CODE"
rst.Seek "=", Me!Combo_Product_number
If Nz(Me!Combo_Product_number) = "" Then
DoCmd.OpenForm "Not_found_Inventory"
ElseIf rst.NoMatch Then
DoCmd.OpenForm "Not_found_Inventory"
Else
DoCmd.OpenForm "FRM_Inventory_A01", WhereCondition:="[PRODUCT_CODE]='" & Me!Combo_Product_number & "'"
End If
The Seek method is only valid on a table local to the opened database.
Use the FindFirst method on a linked table.

Run-time Error 2498 for Append and Make Table Queries Created in VBA

I'm getting a 2498 error and really don't understand why. I'm building a string in VBA and am getting the error with the following line of code...
DoCmd.OpenQuery qdfNew, acNormal
It happened with a very long string created to create the query so I simplified the code as much as possible and am still getting the error.
Here's the code...
Option Compare Database
Option Explicit
Dim dbsFootball As Database
Dim strInsertSQL, strSelectSQL, strIntoSQL, strFromSQL, strOrderSQL, strSQL As String
Dim qdfNew As QueryDef
Sub CreateFormattedData()
Set dbsFootball = CurrentDb()
strSelectSQL = ""
strIntoSQL = ""
strFromSQL = ""
strOrderSQL = ""
strSQL = ""
strSelectSQL = "SELECT [tbl_Raw_League_Data].[Season]"
strIntoSQL = "INTO [tbl_Manip Data]"
strFromSQL = "FROM [tbl_Raw_League_Data]" _
+ "LEFT JOIN Referees ON [tbl_Raw_League_Data].[Referee] = Referees.[Referee from Source Data]"
strSQL = strSelectSQL + " " + strIntoSQL + " " + strFromSQL + " " + strOrderSQL
On Error Resume Next ' If query doesn't exist, error won't stop execution
DoCmd.DeleteObject acQuery, "pgmqry_Create Table tbl_Manip"
On Error GoTo 0 ' Reset error handler
Set qdfNew = dbsFootball.CreateQueryDef("pgmqry_Create Table tbl_Manip", strSQL)
DoCmd.OpenQuery qdfNew, acNormal
End Sub
The source field, [tbl_Raw_League_Data].[Season], is a "Short Text" data type (field size = 7).
If I terminate the VBA code and run the query that was created by the code, it works fine with no apparent errors. However, it will never run the query from within the VBA code.
I was originally getting the error 2498 when using "INSERT INTO" for an append query, but realized that the table could as easily be recreated at code execution time.
I'm lost and would sure appreciate some ideas!
Thanks in advance,
Jason
You are passing the querydef object to DoCmd.OpenQuery when it expects a string referencing name of a stored query object. Consider using the querydef's Name property:
DoCmd.OpenQuery qdfNew.Name, acNormal
Alternatively, use .Execute command from database object using the SQL string variable, bypassing any need for querydef:
dbsFootball.Execute strSQL, dbFailOnError
Or with querydef object, as #HansUp suggests, where you simply execute directly since it is an action query:
qdfNew.Execute dbFailOnError
Do note above two options bring up the regular MS Access discussion, of using stored vs VBA string query. While the former is precompiled and runs through query optimizer caching best plan, the latter can have sql dynamically created (structural components that is like SELECT, FROM and JOIN clauses as both can use passed in parameters). From your code snippet consider saving SQL query beforehand without needing to build it in VBA on the fly, and call it with DoCmd.OpenQuery.