I'm using Access 2013 as a front end with a SQL Server back end, and I'm trying to bind an ADO Recordset to a form, however, the Recordset will only open as Static. So I can see all the records in a datasheet, I just can't edit them.
I can use the connection object to execute an update query, so I don't think that is the issue. I've tried using Dynamic, Keyset and Forward-Only and locking as Batch Optimistic, Optimistic, and Pessimistic to open the Recordset, but still opens as static.
Below code is condensed, but essentially the same, and most importantly, still doesn't work.
Public Sub TestConnect()
Dim objConn As ADODB.Connection
Dim objRS As ADODB.Recordset
Set objConn = New ADODB.Connection
objConn.ConnectionString = "Data Provider=sqloledb;Provider=Microsoft.Access.OLEDB.10.0;Server=REDACTED;Database=REDACTED;Trusted_Connection=Yes"
objConn.CursorLocation = adUseClient
objConn.Open
Debug.Print objConn.state = adStateOpen
Set objRS = New ADODB.Recordset
objRS.CursorLocation = adUseClient
objRS.Open "SELECT * FROM Table1;", objConn, adOpenDynamic, adLockOptimistic
Debug.Print objRS.CursorType
objRS.Close
objConn.Close
End Sub
I've tried looking at a few place, such as https://learn.microsoft.com/en-us/office/vba/access/Concepts/ActiveX-Data-Objects/bind-a-form-to-an-ado-recordset and MS Access Form Bound to ADO Disconnected Recordset, but I'm not having any luck identifying where my issue is.
Any help would be amazing, I'm tearing my hair out here. Thanks!
Related
I have a problem here that I will probably need to solve in several iterations, this being the first. maybe you have an idea:
I need to speed up regular updates from 4 views in an SQL database on Azure to an Excel Worksheet. There are probably a lot of moving parts here, among them: The code, my connection to the internet, the service that provides me with a static IP address, the fact that I reference views and not tables, and the (rather basic) service level I booked in Azure.
What my code does is simple: it opens a connection, updates 4 worksheets from 4 views (3 of them with 5 - 10 rowns of data, 1 with about 2.000), and closes the connection again.
This takes up to 30 seconds, which seems an awfully long time.
I would like to make sure it is not my code that slows this down. My first attemt was to use Powerquery for the connections, call the connection, then set autofilters with VBA to have only the rows visible that I needed. That took ages.
My second try is: not use Powerquery, get rid of the autofilters, and use VBA instead to pass a SELECT to the SQL Server, so the work of selecting the data is done there, and send over only what I need. But it seems the difference that this makes is not really significant.
The code I use is:
Dim WS1 As Worksheet
Set WS1 = Worksheets("Eingabe")
Dim SelectedCustomer As Range
Set SelectedCustomer = WS1.Range("C39")
Dim cn As ADODB.Connection
Dim SQLStr1 As String
Dim rs1 As ADODB.Recordset
Set rs1 = New ADODB.Recordset
Dim SQLStr2 As String
Dim rs2 As ADODB.Recordset
Set rs2 = New ADODB.Recordset
Dim SQLStr3 As String
Dim rs3 As ADODB.Recordset
Set rs3 = New ADODB.Recordset
Dim SQLStr4 As String
Dim rs4 As ADODB.Recordset
Set rs4 = New ADODB.Recordset
'Open a connection to SQL Server - using the connection string provided by Azure
Set cn = New ADODB.Connection
cn.Open "Driver={ODBC Driver 17 for SQL Server};Server=tcp:server-
displacethis.database.windows.net,1433;Database=my-database;Uid=my-userID;Pwd=my-
password;Encrypt=yes;TrustServerCertificate=no;Connection Timeout=30;"
'First table
SQLStr1 = "SELECT CustomerID,CustomerUniqueName,CustomerFirstName,CustomerLastName,TransactionDate,EmissionenNeukauf,EmissionenSecondhand,600 As DurchschnittDE, 300 As Paris2030 FROM vAccumulatedEmissionsByCustomer WHERE CustomerUniqueName = '" & SelectedCustomer & " ' "
rs1.Open SQLStr1, cn, adOpenStatic
'Dump to spreadsheet
With Worksheets("vAccumulatedEmissions").Range("A2:I100")
.ClearContents
.CopyFromRecordset rs1
'Do some column formatting
Worksheets("vAccumulatedEmissions").Range("F:F").NumberFormat = "#,##0.00"
'Tidy up
rs1.Close
Set rs1 = Nothing
End With
'Then the next table follows. The connection os closed after the last table:
cn.Close
Set cn = Nothing
My questions is, very simply, is this highly ineffective code, and could that be the reason for the long time it runs, or should I look somewhere else to speed up the whole process?
Thank you in advance,
Ulrich
I've got a simple MS Access 2013 form with some text boxes, each of whose Control Source is set to fields in an ADODB recordset. The recordset may come from either a table in the current accdb project or as the result of a SQL Server stored procedure; this is set by selecting a radio button on the form.
I've confirmed that each of the two recordsets are updateable in vba code but when I use the form it will only allow me to edit fields returned from the SQL Server option; the Access option displays records but acts as if the text box is locked when I attempt to edit it.
This is the code I'm using:
Private Sub cmdLoadData_Click()
Dim rst As ADODB.Recordset
Set rst = New ADODB.Recordset
With rst
.CursorLocation = adUseClient
.CursorType = adOpenDynamic
.LockType = adLockOptimistic
End With
Select Case BackendOptions
Case 1
' Access
With rst
.ActiveConnection = CurrentProject.AccessConnection
.Open "SELECT Id, FirstName, LastName, Birthday FROM tblADOTest"
End With
Case 2
' SQL Server
Dim cn As New ADODB.Connection
With cn
.ConnectionString = "Driver={SQL Server Native Client 11.0};" & _
"Server=<the server name>;" & _
"Database=<the database name>;" & _
"Trusted_Connection=yes;"
.Open
End With
With rst
.ActiveConnection = cn
.Open "EXEC dbo.GetTestData"
End With
End Select
Set Me.Recordset = rst
End Sub
The stored procedure runs the same SQL as the inline string I'm using for Access.
Any ides on how to make the Access option editable?
helped me solve a similar problem using this:
.ActiveConnection = CurrentProject.Connection
I'm trying to read a particular column value from a SQL result table. I know we use RowCount in c#. But I don’t know how it is done in vb6.0
For example a c# program code:
adapter.Fill(ds);
adapter.Dispose();
con.Close();
rowCount = ds.Tables[0].Rows.Count;// ds is dataset and I read that record set is used instead of dataset
if (rowCount > 1)
{
ab = ds.Tables[0].Rows[0][3].ToString();
ad = ds.Tables[0].Rows[0][8].ToString();
}
In VB6 you have a choice of ADO, DAO or RDO. ADO is newer of the three technologies, and the one MS recommends.
ADO Example
Sub Example()
Dim cn As ADODB.Connection
Dim rs As ADODB.Recordset
' Ready objects for use.
Set cn = New ADODB.Connection
Set rs = New ADODB.Recordset
' Connect.
cn.Open "Driver={SQL Server};Server=My_Server_Name;Database=Master;Trusted_Connection=yes;"
' Fetch a recordset.
rs.Open "SELECT TOP 10 Name FROM sys.Objects", cn, adOpenStatic, adLockReadOnly
' Display value, and total recordcount.
MsgBox rs.Fields(0).Value
MsgBox rs.RecordCount
' Close and release objects.
rs.Close
cn.Close
Set rs = Nothing
Set cn = Nothing
End Sub
The ADO Recordset object has a RecordCount property. Watch out! Certain cursor types do not populate this property. See the link for more on this.
ConnectionStrings.com is a great resource for finding the right connection string for you.
For this example to work you will need to add a reference to the Microsoft ActiveX Data Objects library.
I'm trying to build a VBA form that runs a SQL Server stored procedure to cache data before it does anything else. Ideally I'd prefer not to use an Excel data connection because then I can't export it to a new workbook with a minimum of fuss - it'd be nice to contain all of the information in the form's file.
The main way I know to connect VBA to a database is using code along these lines:
Dim cnn As New ADODB.Connection
Dim rst As New ADODB.Recordset
cnn.Open ConnectionString
rst.Open QueryText, cnn, adOpenDynamic
/*Whatever you're doing to the data goes here*/
rst.Close
cnn.Close
The problem I'm running into is that the caching proc doesn't return a dataset (not even a blank one), and this type of connection seems to throw a tizzy if there is no data returned. And I'd prefer not to modify the proc if I don't have to.
Is there a feasible solution, within these constraints? Or am I just being too whiny and should suck it up and use an Excel data connection or something?
I think you are looking for an ADODB.Command. Try something like this:
Dim cnn As New ADODB.Connection
Dim cmd As ADODB.Command
cnn.Open ConnectionString
Set cmd = New ADODB.Command
With cmd
.ActiveConnection = cnn
.CommandText = "EXEC spNameHere param1"
.CommandType = adCmdText
.Execute
End With
This is my function:
Public Function DBConnection(ByVal path As String)
' This function makes the database connection and returns the object
' to reference it.
cn = New OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0; Data Source=" + path + ";")
cn.Open()
Return cn
End Function
As you can see, I want to initialize a database connection and return it so I can use it in my forms. This function is in a module and my variables are as follows:
Public cn As OleDbConnection
Public cmd As OleDbCommand
Public dr As OleDbDataReader
But I'm not sure how I can use this in my forms, do I just call the function DBConnection and then proceed with my SQL statements? Or do I have to do something else? Help would be very much appreciated, cheers.
Also, I need some opinions. My application relies on a MS Access database. Is it better to initialize the connection on Form_Load and then close the connection when the user closes the program, or open and close the connections as the queries are run? I'm planning to use some database queries on multiple forms hence the reason I was putting it into a module, but I'm not 100% on how I should proceed with this.
Thanks.
From: How to bind Microsoft Access forms to ADO recordsets
Private Sub Form_Open(Cancel As Integer)
Dim cn As ADODB.Connection
Dim rs As ADODB.Recordset
'Use the ADO connection that Access uses
Set cn = CurrentProject.AccessConnection
'Create an instance of the ADO Recordset class, and
'set its properties
Set rs = New ADODB.Recordset
With rs
Set .ActiveConnection = cn
.Source = "SELECT * FROM Customers"
.LockType = adLockOptimistic
.CursorType = adOpenKeyset
.Open
End With
'Set the form's Recordset property to the ADO recordset
Set Me.Recordset = rs
Set rs = Nothing
Set cn = Nothing
End Sub
A couple things. That function will open a connection every time it's called. You better make sure you are closing the database as well, or that will start eating up memory.
You might look at some other options (such as using NHibernate or another ORM.)
However, if you stay with this model, you could then use the cn that is returned to access your database.