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.
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 am trying to read data from oracle using adodb connection object from excel.But I am getting an error " oracle -160000 database was set to read only access".Please let me know how to resolve this.
Look at the recordset open method's LockType parameter and use adLockReadOnly. I'm not familiar with Oracle. You may also need to CursorType parameter to adOpenForwardOnly.
Example:
Dim lobjADOConnection As ADODB.Connection
Dim lobjADOData As ADODB.Recordset
Dim lstrSQL As String
Set lobjADOConnection = New ADODB.Connection
lobjADOConnection.Open ...
Set lobjADOData = New ADODB.Recordset
lstrSQL = "<your query here>"
lobjADOData.Open lstrSQL, lobjADOConnection, adOpenForwardOnly, adLockReadOnly '<===here
If Not lobjADOData.BOF Then
lobjADOData.MoveFirst
Do While Not lobjADOData.EOF
DoEvents
.
.
.
or if you just want to dump the data into a worksheet
Dim lobjTargetSheet As Worksheet
Set lobjTargetSheet = ThisWorkbook.Sheets("<SomeSheetName>")
With lobjTargetSheet
.Select
.Range("1:" & .UsedRange.Rows.count + 1).Delete xlUp
.Range("A1").Select
.Range("A1").CopyFromRecordset lobjADOData
End With
The process is run in the environment of Excel VBA 2010 and MS SQL Server 2008.
Assume that there is a simple one column data with 1500 rows in an Excel-sheet and we want to export it to the database with SQL-queries in VBA code (SQL procedure in VBA exports maximum 1000 rows at once in default mode).
There is one limitation in this problem: the export procedure must be with dbclass-connection instead of ADODB connection. (The code-owner is not me. The code-owner is using dbclass for a quite big VBA code, so probably he wouldn't accept to change the whole code).
I found an option like lngRecsAff for ADODB.Connection which is used like:
Sub test()
Dim cn As ADODB.Connection
Dim strSQL As String
Dim lngRecsAff As Long
Set cn = New ADODB.Connection
cn.Open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\test.xls; Extended Properties=Excel 8.0"
strSQL = "Insert INTO [odbc;Driver={SQL Server};Server=SQL09;Database=Tom;UID=userID;PWD=password].tbl_test1 Select * FROM [Sheet1$]"
cn.Execute strSQL, lngRecsAff
cn.Close
Set cn = Nothing
End Sub
I tried to implement that lngRecsAff in my dbclass execution like:
Sub test()
Dim connOk As Boolean
Dim rs As New ADODB.Recordset
Set dbclass = New clsDB
Dim Value1() As Variant
Dim lngRecsAff As Long
Dim strSQL as String
Dim mstrErr as Boolean
dbclass.Database = "database_name"
dbclass.ConnectionType = SqlServer
dbclass.DataSource = "server_name"
dbclass.UserID = Application.UserName
connOk = dbclass.OpenConnection(False, True)
If connOk = False Then
MsgBox "Unsuccessful connection!"
Else
MsgBox "Successful connection"
End If
strSQL = "INSERT INTO [dbo].[table1](Column1) Values('" & Value1 & "')"
mstrErr = dbclass.ExecuteSQL(strSQL, lngRecsAff) ' The result mstrErr is a Boolean
' Some closing options here
End Sub
I got en error like lngRecsAff is not suitable for my ExecuteSQL procedure. Normally my execution mstrErr = dbclass.ExecuteSQL(strSQL) works without any problem.
Maybe I can do the SQL-procedure with a for-loop, then I can send the data in small pieces. But I want to find a more efficient, "nicer" solution which sends the whole array at once.
So is there any special option for dbclass which can send more than 1000 rows from Excel to the database?
You can query the Excel-Sheet directly using liked server.
In your Management Studio click to "Server Objects" and then right click onto "linked server". There you'll be able to add a new linked server.
If you need further help you can find tuorials easily. One is here:
https://www.mssqltips.com/sqlservertip/2018/using-a-sql-server-linked-server-to-query-excel-files/
So here's my dilemma I'm attempting to create a macro that runs a query out of sql that located in cell (Sheets("SQL").Range("G1")), and paste the data from that query into Sheets("Data").Range("B1"). I came up with the code below but I keep getting a compile error: User-defined type not defined. Please any insight on what I'm doing wrong will be appreciated.
Sub ConnectSqlServer()
Dim conn As ADODB.Connection
Dim rs As ADODB.Recordset
Dim sConnString As String
Dim StrSQL As Variant
Application.ScreenUpdating = False
Application.Cursor = xlWait
Set cnPubs = New ADODB.Connection
Set rsPubs = New ADODB.Recordset
StrSQL = " SET NOCOUNT ON "
' Create the connection string.
sConnString = "Provider=SQLOLEDB; DATA SOURCE=CFS-SERVERSQL;" & _
"Initial Catalog=dmtrans;" & _
"Integrated Security=SSPI;"
' Create the Connection and Recordset objects.
Set conn = New ADODB.Connection
Set rs = New ADODB.Recordset
' Open the connection and execute.
conn.Open sConnString
Set rs = conn.Execute(Sheets("SQL").Range("G1"))
' Check we have data.
If Not rs.EOF Then
' Transfer result.
Sheets("Data").Range("B4:S50000").ClearContents
Sheets(Data).Range("b4").CopyFromRecordset rs
' Close the recordset
rs.Close
Else
MsgBox "Error: No records returned.", vbCritical
End If
' Clean up
If CBool(conn.State And adStateOpen) Then conn.Close
Set conn = Nothing
Set rs = Nothing
End Sub
You probably did not set the reference for your ADODB objects.
You can either do this with early binding:
(Don't know the names exactly. I am using a german Excel)
Extras - References: Add the reference Microsoft ActiveX Data Objects vXXX with a click in the checkbox to your project.
Or you can do this via late binding. In this case you must declare your variable as Object and instantiate it via CreateObject. Please find a related question here: Excel VBA: Late binding reference
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.