How to begin new transaction using ADO - vba

I've tried
CurrentProject.Connection.BeginTrans
' This acts as if you didn't begin a transaction.
' Changes are posted real time then gets an error on Commit that you are not in a transaction
Private conn As ADODB.Connection
Set conn = CurrentProject.Connection
conn.BeginTrans
' This fails silently in the sense that nothing posts to the database when it gets committed
Set conn = New ADODB.connection
conn.Open GetConnectionString
conn.BeginTrans
' This fails on the first SQL statement with
' "Object variable or with block variable not set"
' But it clearly is set because it works if I don't start a transaction
' You would think that starting a transaction explicitly would work.
Private conn As ADODB.Connection
Set conn = CurrentProject.Connection
conn.Execute "Begin Transaction", , adCmdText Or adExecuteNoRecords
' This also fails silently in the sense that nothing posts to the database when it gets committed.
Commit looks just as you would expect. Whichever of these is appropriate:
CurrentProject.Connection.CommitTrans
conn.CommitTrans
conn.Execute "Commit Transaction", , adCmdText Or adExecuteNoRecords
Nothing works.
I can easily get it to work on DAO.
DAO.Workspace.BeginTrans
works just as you would expect, except that only DAO statements are committed. Anything posted through ADO is lost, disappearing as if they didn't happen.
But I don't want to switch hundreds of SQL routines to use DAO if I can avoid it.
Note that I'm not trying to create a new connection to the back end. These are all linked tables, with Access compatible SQL statements.
The solution I posted here, doesn't appear to be working after all.
What is the recommended approach to transactions in ADO on local tables?

Related

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

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

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.

Connection to SQL Database

I am Making connection to Sql Database and in one connection i am changing my query many
times,This is the basic structure of my code.The structure works fine.
I have Following Questions
1) Is this the right method of sending different Query to Sql Database.
2) Will this cause any memory leaks or error.
dim conn
set conn=CreateObject("ADODB.Connection")
With conn
.Provider = "Microsoft.Jet.OLEDB.4.0"
.ConnectionString ="Data Source=C:\MAP_sample.xls;" & "Extended Properties=Excel 8.0;"
.Open
End With
Set rs = CreateObject("ADODB.Recordset")
Query = "SELECT * FROM [Sheet1$] where StateName='ABC'"
rs.Open Query,conn
rs.close
CHANGE THE QUERY
Query = "SELECT * FROM [Sheet1$] where ID='321'"
rs.Open Query,conn
rs.close
change the query
Query = "SELECT * FROM [Sheet1$] where NAME='SMITH'"
rs.Open Query,conn
rs.close
Set rs = nothing
conn.close
Set conn = nothing
looks like classic ASP with visual basic.
It is one of the possible variants to send queries, it is not bad, a little bit boilerplate, as suggestion - try to re-factor it into separate class or functions
No, it will no cause memory leaks or errors as you're calling close
You can later call the Open method to re-establish the connection to the same, or another, data source.
the only problem with this approach comes when you need to have 2 recordset opened at the same time
if you speak about general code readability - it is better to use meaningful variable names

How Do I Return Multiple Recordsets from SQL Stored Procedure in Access 2010

I’ve created a pass-through query in Access which executes a stored procedure that searches for a string across all tables in my SQL database. The stored procedure on the SQL server runs as expected, returning multiple Recordsets that contain the value of my search string. However, when I double-click on the pass-through query in Access, in Datasheet View I see the results of only one Recordset. Since it appears that Access is not designed to handle multiple result sets, then how do I use VBA in Access to accomplish this?
exec sqlsp_searchalltables #Tablenames='', #SearchStr='%motion%'
I'm not quite sure how you expected to "bind" your form to the multiple recordsets returned by the stored procedure, but as far as I know the only way to deal with SQL Server stored procedures that return multiple recordsets is to use ADODB.Recordset objects.
(Don't be misled by the "Recordset.NextRecordset Method (DAO)" article here. If you try that approach you will receive run-time error '3847': "ODBCDirect is no longer supported. Rewrite the code to use ADO instead of DAO.")
For example, I have a SQL Server stored procedure that returns two recordsets and I create a pass-through named [dbo_myMultiRsSp_1] to call it:
EXEC dbo.myMultiRsSp #id=1
If I open it in Datasheet View by double-clicking it I see the results of the first recordset.
If I want to process all of the recordsets in VBA I cannot use the pass-through query directly, but I can use its .Connect and .SQL properties as follows
Option Compare Database
Option Explicit
Sub MultiRsSpTest()
Dim cdb As DAO.Database
Dim con As ADODB.Connection, cmd As ADODB.Command
Dim r1 As ADODB.Recordset, r2 As ADODB.Recordset
Set cdb = CurrentDb
Set con = New ADODB.Connection
' connect directly to the SQL Server
' (by using the .Connect property of the pass-through query)
con.Open Mid(cdb.QueryDefs("dbo_myMultiRsSp_1").Connect, 5) ' omit "ODBC:" prefix
Set cmd = New ADODB.Command
cmd.ActiveConnection = con
cmd.CommandType = adCmdText
cmd.CommandText = cdb.QueryDefs("dbo_myMultiRsSp_1").SQL
Set r1 = cmd.Execute
Debug.Print
Debug.Print "First Recordset:"
Do Until r1.EOF
Debug.Print r1(0).Value
r1.MoveNext
Loop
Set r2 = r1.NextRecordset
Debug.Print
Debug.Print "Second Recordset:"
Do Until r2.EOF
Debug.Print r2(0).Value
r2.MoveNext
Loop
' r1.Close (happens implicitly)
Set r1 = Nothing
r2.Close
Set r2 = Nothing
Set cmd = Nothing
Set con = Nothing
Set cdb = Nothing
End Sub

Rowset does not support scrolling backward

I am trying to query a MySQL database with the below code:
'declare the variables
Dim Connection
Dim Recordset
Dim SQL
'declare the SQL statement that will query the database
SQL = "SELECT * FROM CUSIP"
'create an instance of the ADO connection and recordset objects
Set Connection = CreateObject("ADODB.Connection")
Set Recordset = CreateObject("ADODB.Recordset")
'open the connection to the database
Connection.Open "DSN=CCS_DSN;UID=root;PWD=password;Database=CCS"
Recordset.CursorType=adOpenDynamic
'Open the recordset object executing the SQL statement and return records
Recordset.Open SQL,Connection
Recordset.MoveFirst
If Recordset.Find ("CUSIP_NAME='somevalue'") Then
MsgBox "Found"
Else
MsgBox "Not Found"
End If
'close the connection and recordset objects to free up resources
Recordset.Close
Set Recordset=nothing
Connection.Close
Set Connection=nothing
Whenever I execute the above I get an error 'rowset does not support scrolling backward', any suggestions?
adOpenDynamic is not declared in VBScript and therefore equals Empty, which gets converted to 0 when you assign the CursorType property.
0 is adOpenForwardOnly, and forward only does not support moving backwards, an ability the Find method wants.
You should replace adOpenDynamic with its literal value:
Recordset.CursorType = 2 'adOpenDynamic
To avoid this class of errors altogether, place Option Explicit as the first line of your script.
That is because the rowset does not permit backward moves; as the error message suggests. Your code is not using them; so you should replace the line
Recordset.CursorType=adOpenDynamic
with
Recordset.CursorType=adOpenForwardOnly (or the equivalent value 0)
Better leave the line altogether; the default is forward cursor.