ADODB in Access - Will not insert, but does not raise error - vba

I've been staring at this the past few hours-- I figure now that there is some subtle and devious bug in MySQL causing this, or it's an incredibly obvious solution and I just need another set of eyes. I'd appreciate any help.
I'm using Access to do some data entry work. I have the tables I am working with linked, but I'm primarily dealing with them through explicit ADODB connections (Which will hopefully make transactions easier and allow me to use SELECT ##IDENTITY). The tables are in MySQL on an server within my environment.
I've done similar work before, but for some reason now no updates are made. It doesn't raise an error, I've checked the Connection's error property...for some reason it just breezes through this code without raising an error. The table being referenced is completely empty now, it has quite a few fields but only 2 are that required - an autonumber ID and the field being populated.
Can anyone see something blatantly wrong here? Option Explicit is on, it seems like it's making the connection fine, otherwise I imagine it would error when opening the recordset or connection. Does anyone have any debugging suggestions?
One last note, the code was more complicated - I'm experimenting with making a class to store my connection, to make those things I described easier. My worst-case thought it something I did there, like beginning a transaction without closing it, has caused something to hiccup in MySQL.
Sub ADODBError()
Dim cnn As ADODB.Connection
Set cnn = New ADODB.Connection
cnn.Open "driver={mysql odbc 5.2a driver};" & _
"server=my.mysql.server;" & _
"user=myUser;password=myPwd;" & _
"database=callcenter"
Dim firstDayOfWk As Date
firstDayOfWk = #8/18/2014#
Dim rst As ADODB.Recordset
Set rst = New ADODB.Recordset
rst.Open "WeeklyCallCenterStats", cnn, adOpenForwardOnly, adLockBatchOptimistic, adCmdTable
With rst
.AddNew
.Fields("WeekStarting") = firstDayOfWk
.Update
.Close
End With
End Sub

When you open a ADO recordset in batch locking mode, the changes you make to the recordset are not actually transmitted until you call UpdateBatch on the recordset.
Change the locking mode in your rst.Open call (I recommend adLockOptimistic unless it's a quickly changing table), or call rst.UpdateBatch after making your changes.

Related

MS Access crashes binding RS to a form from SQL Server stored procedure

I am just starting to move our Access DB to SQL Server and am having trouble.
I have a stored procedure that successfully returns rows to an ado recordset.
When I try to bind the rs containing the results of the stored procedure to the Access form, Access crashes without displaying any error messages. I'm on O365 32b and SQL Server 2019.
Here's the code:
Dim sSQL As String, rs As ADODB.Recordset
1 sSQL = "Exec usp_TaskStatusWidget " & Me.Tag & ",0"
2 ADOConn.ConnectionString = conADO
4 ADOConn.Open
6 Set rs = New ADODB.Recordset
7 rs.CursorLocation = adUseClient
8 rs.Open sSQL, ADOConn
10 Set Me.Recordset = rs ' Access crashes here
. . .
Any help would be greatly appreciated!
tia.
SR
Ok, are you previous using ADO, or are you just introducing this?
In most cases, you are better off to just use a view. (replace the access query with a linked view), and then continue useing client side where clauses or filters (access will ONLY pull down the rows you request). So linked views are often a better choice and much less work (in fact, even existing filter for a open report etc. will work and only critera matching the were clause records are pulled.
And in most cases, i don't introduce ADO.
So for a PT query, I often do this:
dim rs as DAO.RecordSet
with CurrentDb.queryDefs("qryPt")
.SQL = "Exec usp_TaskStatusWidget " & Me.Tag & ",0"
set rs = .OpenRecordSet
end with
So, above assumes you have a pt query called qryPt. This also means that you never deal with or worry about connection strings in code. The pt query has the connection. (and your re-link code now can re-link tables and pt queries).
I ONLY suggest the above as a FYI in case that you introducing ADO for calling store procedures, and the rest of the application was previous DAO. If the application was previous DAO, then leave it alone, and use above approach for your PT queries - even code that needs to call store procedures.
Access tends to try and parse the query text to get filters/sorts/etc to work, and if it isn't a plain syntax error but isn't Access SQL either, strange things tend to happen, mostly crashes.
Try adding a comment up front to make sure Access knows not to parse:
sSQL = "-- Access no parse pls" & vbCrLf & "Exec usp_TaskStatusWidget " & Me.Tag & ",0"
The content of the comment is not relevant, of course, its purpose is to immediately cause a syntax error when Access tries to parse it as Access SQL (which doesn't have comments)

EOF value is always true even if there is record returned from VBA SQL

I am querying my access table using VBA and writing the query result in excel.
EOF is always true but BOF is False - even if the record count is 1 or 14 or 100. What possibly would be wrong? I can see the record count more than zero. get string value has data in it. Due to this there is no data written in the destination sheet except for Headers. The headers are coming in fine.
List of things tried but result was still same:
Added Move last and Move first command
Tried all possible combinations of Cursor location, cursor type, lock type
Tried with execute command
Tried with different MS access table
Tried early and late binding techniques
Below is my query and link below is my how my record set looks after SQL open statement.
Const MyConn = "Access DB location"
Dim con As ADODB.Connection
Dim rs As ADODB.Recordset
Set con = New ADODB.Connection
With con
.Provider = "Microsoft.ACE.OLEDB.12.0"
.Open MyConn
End With
QuerySql = "SELECT * FROM Store_Location"
Set rs = New ADODB.Recordset
rs.CursorLocation = adUseClient
rs.Open QuerySql, con, adOpenStatic, adLockReadOnly, adCmdUnknown
rs.MoveLast
rs.MoveFirst
i = 0
For i = 0 To rs.Fields.Count - 1
Sheets("Search_Temp").Cells(1, i + 1) = rs.Fields(i).Name
Next i
Range("A2").CopyFromRecordset rs
rs.Close
Set rs = Nothing
con.Close
Set con = Nothing
While debugging this is what my record set looks like:
Building on this answer to a similar question, calling getString on a Recordset object has a side-effect of moving the recordset to EOF.
You don't call getString anywhere in your code but you've added a watch on rs.getString which is visible as the last entry in the Watches window. If you have a watch on rs.getString and you have a breakpoint in the code where rs is open then that breakpoint will cause the recordset to move to EOF.
Depending on where the breakpoint occurs, this might not cause any issues (e.g. if the recordset was already at EOF) but, in this case, it is moving the recordset to EOF before you have copied the data from the recordset.
To solve this issue, remove the watch on rs.getString. It's probably a bad idea in general to have items in the Watches window cause side effects. You could also avoid the issue by not having any breakpoints where the recordset is open but removing the watch entirely is more robust.
The issue of getString moving the recordset to EOF isn't mentioned in the ADO documentation but it's easy to reproduce this effect.
It's uncommon for someone to include the entire list of watches they had set in their question but I'm not sure this question was answerable without that information

VBA ADO Insert failing silently (no errors)

I have a really frustrating issue. I have an insert query that will run fine if you run it from within access (takes ~ 2 minutes to complete) but when I try to run it programatically from Excel via ADO, the .execute line actions in seconds with no errors, but does not actually insert any data to the table.
The ADO I use is below:
With objCommand
.ActiveConnection = p_moConn
.CommandType = adCmdStoredProc
.CommandText = "[" & strQueryName & "]"
.Execute
End With
I have also tried:
p_moConn.Execute strSQL, adCmdText
With exactly the same result. (strQueryName is the name of the saved procedure, strSQL is the raw SQL)
BTW, before we get into it, i'm not using DAO as this is a prototype that will be migrated from Access to a "main" database system and the only code change necessary should be the connection string... fingers crossed...
Any help is appreciated!
Thanks
Matt
Cheers for the help, it was something to do with those 5 queries. I can't post the SQL (apart from anything else it is long...) but because of the length and complexity Access was "fiddling" with it internally. Namely it added something to the very end of the query:
AS [%$###_Alias];
When I change that to:
AS [test];
The ADO code runs it perfectly! As an aside, I believe the reason I was getting no error was because I was looking at the VBA Error object and not the ADO one which I think it found in:
.ActiveConnection.Errors()
But that is untested
Thanks again guys!
Matt
BTW, I found this thanks to Wayne G. Dunn as when I looked at the code to see if I could sanitize it before posting I finally noticed the last line that Access had changed... so cheers ;-)

VB.net Getting Scalar to save a value to a variable

I've been looking through the forums with no luck. I am trying to retrieve a value from a database and store it to a variable. The closest I got was following This. Here is my Code:
Dim dblAircraftHourlyRate As Double
Dim intAircraftID As Integer
intAircraftID = ddAircraft.SelectedItem.Value
Dim mySqlComm As String = "SELECT HourlyRate FROM Aircraft WHERE AircraftID = '" & intAircraftID & "'"
Using cn As New SqlConnection("Data Source=.\SQLEXPRESS;AttachDbFilename=C:\Users\Rollin Laptop\Desktop\CurrentAll2Fly3\App_Data\ASPNETDB.MDF;Integrated Security=True;User Instance=True"), _
cmd As New SqlCommand(mySqlComm, cn)
cn.Open()
dblAircraftHourlyRate = Convert.ToDouble(cmd.ExecuteScalar())
End Using
I'm not sure why, but instead of saving the HourlyRate to the dblAircraftHourlyRate, it is saving the intAircraftID to dblAircraftHourlyRate. I'm also not sure why the example code did not close the database connection. Any ideas on how to fix this to get the correct variable?
My solution had nothing to do with the question, but I had a separate bit of code that was executing after the bit I posted. It was resetting the value of dblAircraftHourlyRate such that dblAircraftHourlyRate = ddAircraft.SelectedItem.Value After I commented out the line, the code worked perfectly. To clarify, the value in the dropdownlist was the AircraftID, not the HourlyRate.
Tim Schmelter also helped me out in his explanation of how Connection-Pooling works:
Connection-Pooling is enabled by default. Default means that it's enabled even if you don't specify the Pooling parameter in your connection-string. Connection-pooling helps to improve performance since it maintains the state of the physical connections. So even if you close a connection the physical connection keeps open (If you check it in the database). You are using the Using-statement which is best practise. Disposing a connection will "close" it. – Tim Schmelter

Record locking in vba

i have a VBA application which is spitted into two one for front end; and backend while updating how to prevent two users edit it ??
Access has locking. From Access Help:
Specify the locking level used in an Access database in a multiuser environment
On the Tools menu, click Options.
Click the Advanced tab.
To make record-level locking the new
default setting for the current
Microsoft Access database, select the
Open databases using record-level
locking check box.
To make page-level
locking the new default setting for
the current Access database, clear the
Open databases using record level
locking check box.
Notes
This setting takes place the next time
you open the Access database, but you
must use the Open command on the File
menu rather than the list of most
recently used files at the end of the
File menu. This behavior is the same
as the setting for the default open
mode.
If you select Open databases using
record level locking, this becomes the
default behavior for access to data
through a form, a datasheet, and code
that uses a recordset object to loop
through records, but not through
action queries, nor through code that
performs bulk operations using SQL
statements. For more information, see
Chapter 16, "Multiuser Database
Applications," in the Microsoft Office
2000/Visual Basic Programmer's Guide.
Yoy may try to invoke pessimistic locking
Dim cnn As ADODB.Connection
Dim rst As ADODB.Recordset
Set cnn = New ADODB.Connection
cnn.ConnectionString = " Provider=sqloledb;" & _
"Data Source=(local);Initial Catalog=pubs;uid=sa;pwd="
cnn.Open
Set rst = New ADODB.Recordset
rst.ActiveConnection = cnn
rst.CursorType = adOpenKeyset
rst.LockType = adLockPessimistic 'Invoke Pessimistic Locking
rst.CursorLocation = adUseServer
rst.Open "Select * from Table Where ID ='" _
& strID & "'", _
Options:=adCmdText
rst!Name = "New name" 'Lock occurs here
'... when it is locked, you may do other operations
rst.Update 'Lock Released Here
You will have to implement error handling, because when 2nd client wants to edit and cannot lock the record during timeout, error will be raised.
However pessimistic locking is not the best scenario, I would think about optimistic locking and either First Wins or Last Wins strategy
Here is an online book Alison Balter's mastering Microsoft Access 2000 development, it should help you.