Hi I'm trying to program a file to get data from SQL to an array in VBA.
First I tried to use this code and worked with my computer, but after testing the file in other users computer I found the error type-2146825287 when the macro got to the place where it opens the connection. I'm not part of IT department so I will not be able to update the users Service Packs so I tried to reuse another code made by other user that worked for another file some years ago.
This was my first aproach:
Function ConsultaQueryADODB(ConexionString, Query) As Variant
Dim CnADODB As ADODB.Connection
Set CnADODB = New ADODB.Connection
CnADODB.ConnectionString = ConexionString
CnADODB.Open
Dim RsADODB As ADODB.Recordset
Set RsADODB = New ADODB.Recordset
/// Open RecordSet
Set RsADODB = CnADODB.Execute(Query)
///Keep the Recordset using an Array
Dim ArrayQuery As Variant
ArrayQuery = RsADODB.GetRows
RsADODB.Close
Set RsADODB = Nothing
ConsultaQueryADODB = ArrayQuery
End Function
In the old file I found, the programmer was able to connect to the DB and it worked in other users computers. This was his code:
Public Sub QueryBrand()
Dim cn As Object
Set cn = CreateObject("ADODB.Connection")
cn.ConnectionString = "driver={SQL Server};server=SERVERNAME;database=BDInfo;uid=Hello;pwd=Hi"
Dim rst As Object
cn.Open
Set rst = CreateObject("ADODB.Recordset")
Sql = "SELECT distinct Brand FROM BlablaTable order by Brand"
rst.Open Sql, cn, 1, 3
c = 0
f = 2
Sheets("Sheet1").Activate
Range("B2").Select
Range(Selection, Selection.End(xlDown)).Select
Selection.ClearContents
Do While Not rst.EOF
Hoja2.Cells(f, 2) = rst.Fields("Marca")
f = f + 1
rst.MoveNext
Loop
On Error Resume Next
rst.Close
cn.Close
Set cn = Nothing
Set rst = Nothing
End Sub
I tried to modify this code to use it like my first aproach to save the recorset to an array. Now I'm able to open the connection and to open the recordset, but I'm not able to use the GetRows Method cause it becomes an Error 3021. Again in my computer it runs well, but when I run it in another computer it doesnt.
This is my second aproach:
Function ConsultaQueryADODB(ConexionString, Query) As Variant
Set CnADODB = CreateObject("ADODB.Connection")
CnADODB.ConnectionString = ConexionString
Dim RsADODB As Object
CnADODB.Open
Set RsADODB = CreateObject("ADODB.Recordset")
'/// Open the RecordSet
RsADODB.Open Query, CnADODB
'///Save the recordset into an array
Dim ArrayQuery As Variant
ArrayQuery = RsADODB.GetRows '----HERE APPEARS AN ERROR 3021 in the others computers
RsADODB.Close
Set RsADODB = Nothing
ConsultaQueryADODB = ArrayQuery
CnADODB.Close
Set CnADODB = Nothing
End Function
Is there any alternative to populate an array without using the GetRows Method? Do you have some alternatives for this code o connection?
Thanks in advance for your help!
Try the following code below. If not records are returned, the array will be empty which you'll need to check.
Function ConsultaQueryADODB(ConexionString, Query) As Variant()
Set CnADODB = CreateObject("ADODB.Connection")
CnADODB.ConnectionString = ConexionString
Dim RsADODB As Object
CnADODB.Open
Set RsADODB = CreateObject("ADODB.Recordset")
'/// Open the RecordSet
RsADODB.Open Query, CnADODB
'///Save the recordset into an array
If Not RsADODB.BOF And Not RsADODB.EOF Then
ConsultaQueryADODB = RsADODB.GetRows()
End If
RsADODB.Close
Set RsADODB = Nothing
CnADODB.Close
Set CnADODB = Nothing
End Function
Related
I can't keep Access Application Window from displaying when accessing an Access RecordSet from Word VBA.
I have VBA code in Word that creates an Access RecordSet from SQL, manipulates the RecordSet and then closes the Database. I have used Application.ScreenUpdating = False and set the Access Database object .Visible = False, but the Access Application Window keeps flashing on screen for an instant when the code runs.
Code fragment:
Dim acc as Access.Application
Dim db as Database
Dim rst as Recordset
Application.ScreenUpdating = False
Set acc = New Access.Application
With acc
.Visible = False
.OpenCurrentDatabase stAccPath
Set db = .CurrentDb
Set rst = db.OpenRecordset(stSQL)
Other code for manipulating recordset here.
.Quit
End With
set rst = Nothing
Set acc = Nothing
Application.ScreenUpdating = True
What I want to happen is to have Access running invisibly in the background when this code is executed, but in practice, the Access Application window appears on screen for a second before disappearing.
If the code does not need to interact with the user in the Access environment then it's better to not open the database at all. Instead, use an ADO connection retrieve the data directly from data storage, rather than opening the database in Access. This will not only avoid the problem with handling the (unwanted) Access application window, it will also be faster.
Here's some sample code for connecting to an Access database (both mdb and accdb connection strings are provided).
Sub AdoConnectAccess()
Dim conn As ADODB.Connection
Dim rs As ADODB.Recordset
Dim sConn As String, sSQL As String
'sConn = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\myFolder\myAccessFile.accdb"
'sConn = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\myFolder\myAccessFile.mdb"
sSQL = "SELECT * From [Table Name]"
Set conn = New ADODB.Connection
conn.ConnectionString = sConn
conn.Open
Set rs = conn.Execute(sSQL)
rs.MoveFirst
Debug.Print rs.RecordCount, rs.Fields.Count
Do While Not rs.EOF
Debug.Print rs.Fields("Vorname").value
rs.MoveNext
Loop
rs.Close
Set rs = Nothing
conn.Close
Set conn = Nothing
End Sub
I connect Access database to Excel by VBA, importing data from a single table,"Category" , to the worksheet. code below but, instead of table, can I import Query that already exists in the database?
It show "error" when I change the Table name to the Query name in line 15.
'connection Declairation
Dim conn As ADODB.Connection
Dim data As ADODB.Recordset
Set conn = New ADODB.Connection
Set data = New ADODB.Recordset
' end of connection Declairation
conn.ConnectionString = ConstrAccess
conn.Open
On Error GoTo closeconnection
With data
.ActiveConnection = conn 'specfied the connection
.Source = "Category" ' works only for Table Type
.LockType = adLockReadOnly
.CursorType = adOpenForwardOnly
.Open
End With
On Error GoTo closerecordset
Datasheet.Range("a2").CopyFromRecordset data
On Error GoTo 0
closerecordset:
data.Close
closeconnection:
conn.Close
End Sub
Why don't you change to Recordset and TableDef? You won't need to open the DataBase either that way; Add a Reference (tools->references) for Microsoft Office xx.x Access database engine Object Library
Sub test()
Dim BDAnalyzed As Database
Dim RecordTable As Recordset
Dim RecordTableDef As TableDef
Dim CounterTitles As Long
Const DesiredQuery = "Title For Query"
Const PathToDB = "C:..."
Set BDAnalyzed = DBEngine.Workspaces(0).OpenDatabase(PathToDB)
Set RecordTable = BDAnalyzed.OpenRecordset(DesiredQuery, dbOpenDynaset)
Set RecordTableDef = BDAnalyzed.TableDefs(RecordTable)
For CounterTitles = 0 To RecordTableDef.Fields.Count - 1
MsgBox RecordTableDef.Fields(CounterTitles).Name
Next CounterTitles
End Sub
I am trying to run a SP inside a function in an excel macro (button):
Sub Button13_Click()
Call exec_sp_GetLoan_CFM_Info_by_customerID("B3", 2, 1)
Call exec_sp_GetLoan_CFM_Info_by_customerID("B24", 3, 1)
Call exec_sp_GetLoan_CFM_Info_by_customerID("B45", 4, 1)
Call exec_sp_GetLoan_CFM_Info_by_customerID("B66", 5, 1)
Call exec_sp_GetLoan_CFM_Info_by_customerID("B86", 6, 1)
End Sub
The SP returns a single row every time, and I'm trying to write a row with every result set. What happens is that I'm getting a single row in the spreadsheet, for example, as it is shown above, I would only get row 2 with result set for custID from B3. If I comment out the first line, I would only get row 3 with results for custID from B24, and so on. I can never get more than 1 row, and I don't understand why (I'm completely new to vb and excel macros). Can anybody explain what's happening? This is happening even if I don't clear any rows... thank you!
Update: If I set up separate buttons for each 'Call' of the function, it runs fine...
Function exec_sp_GetLoan_CFM_Info_by_customerID(custIDcell As String, stRow As Integer, stCol As Integer)
Dim con As ADODB.Connection
Dim cmd As ADODB.Command
Dim rs As ADODB.Recordset
Dim WSP1 As Worksheet
Set con = New ADODB.Connection
Set cmd = New ADODB.Command
Set rs = New ADODB.Recordset
Application.DisplayStatusBar = True
Application.StatusBar = "Contacting SQL Server..."
' Log in
con.Open "Provider=SQLOLEDB;Data Source=xxxx;Initial Catalog=xxxx ID=xxxx;Password=xxxx;"
cmd.ActiveConnection = con
' Set up the parameter for the Stored Procedure
cmd.Parameters.Append cmd.CreateParameter("custID", adVarChar, adParamInput, 8, Range(custIDcell).Text)
Application.StatusBar = "Running stored procedure..."
cmd.CommandText = "sp_GetLoan_CFM_Info_by_customerID"
Set rs = cmd.Execute(, , adCmdStoredProc)
Set WSP1 = ActiveWorkbook.Worksheets("CIFInfo")
WSP1.Activate
'clear row
WSP1.Rows(stRow).Clear
If rs.EOF = False Then WSP1.Cells(stRow, stCol).CopyFromRecordset rs
'cmd.Parameters("custID").Value = Range("B24").Text
'cleanup
rs.Close
Set rs = Nothing
Set cmd = Nothing
con.Close
Set con = Nothing
Application.StatusBar = "Data successfully updated."
End Function
Beginner's (Excel) mistake... after calling the function with the SP for the first time, the active worksheet gets changed to a different one from the input, so subsequent calls are done with an empty input parameter!!
That wasn't obvious from the post.. sorry!!
Any help with this issue is greatly appreciated.
I am trying to retrieve from Access, by means of Select, multiple values with the same ID and have it pasted into an Excel sheet. I am running the code from Excel VBA.
The query I am using to retrieve said values is:
SELECT Role
FROM Roles
WHERE App_ID=(SELECT ID FROM Apps WHERE NAME='app name');
which is assigned to a variable and afterwards executed by using Set variable = cn.Execute(variable). The problem is that this query, executed from Excel VBA, returns only the first value found. Now, if I run this query from Access it returns every value with the ID for the specified app.
I have tried tried using INNER JOIN, IN, HAVING, etc. but it just wont retrieve all of the values into Excel. Like I said, the query works fine when used in Access so I know this must be limitation in Excel.
Thank you for any help you guys can provide.
Assuming you are using ADODB in Excel, keep in mind that the Execute function returns a Recordset. You can loop through the Recordset to see the additional rows.
Set rng = ActiveSheet.Range("A2")
Set rst = cn.Execute(strSQL)
With rst
Do While Not .EOF
rng = CStr(!Role)
Set rng = rng.Offset(1)
.MoveNext
Loop
End With
'Applies to Access 2010
'Reference Microsoft ActiveX Data Objects 6.1 Library
Dim strSQL As String
Dim strDBPathName As String
Dim strConProvider As String
Dim strPersist As String
Dim conADODB As ADODB.Connection
Dim rsADODB As ADODB.Recordset
Set conADODB = New ADODB.Connection
strConProvider = "Provider=Microsoft.ACE.OLEDB.12.0;"
'Database path name
strDBPathName = "Data Source=C:\Temp\Database.accdb;"
strPersist = "Persist Security Info=False;"
With conADODB
.ConnectionString = strConProvider & strDBPathName & strPersist
.Open
End With
strSQL = "SELECT Role FROM Roles WHERE App_ID=(SELECT ID FROM Apps WHERE NAME='app name')"
Set rsADODB = New ADODB.Recordset
With rsADODB
.Open strSQL, conADODB, adOpenStatic, adLockPessimistic
If Not (.EOF And .BOF) Then
'Range of spreadsheet to paste records
Cells(1, 1).CopyFromRecordset rsADODB
End If
.Close
End With
Set rsADODB = Nothing
conADODB.Close
Set conADODB = Nothing
I was trying to write a VBA to run a query assigned to MySQL only when the HCR_DM.HCR_DM_FACT table is fully loaded. I'm using the count of distinct source in that table to decide if it is fully loaded.
When I was running the Macro below, I got an error message for the Do While line, saying that Object doesn't support this property or method.
I'm quite new to VBA, and I couldn't figure out what need to be adjusted. Can some one help me with this?
Thanks!
Const CNSTR = "Provider = OraOLEDB.Oracle; Data Source =CSDPRO; ODBC;DRIVER={Oracle ODBC Driver};SERVER=CSDPRO;User ID=HCR_SANDBOX;password=******"
Sub FillWithSQLData(strSQL As String, wkSht As String)
' Given a SQL query and worksheet, fills the worksheet with a data dump of the SQL query results
' Define variables
Dim cn As ADODB.Connection
Dim rs As ADODB.Recordset
Dim sql_count As String
' Set variables
Set cn = New ADODB.Connection
Set rs = New ADODB.Recordset
' Connect to SQL Server
With cn
.ConnectionString = CNSTR
.Open
End With
' Query SQL Server and return results as a data dump in cell A2 of the specified worksheet
With rs
.ActiveConnection = cn
sql_count = "select count( distinct a.src_table) from hcr_dm.hcr_dm_fact a"
Set rf = cn.Execute(sql_count)
Do While rf.Fields.Value = 8
.Open strSQL
Loop
Worksheets(wkSht).Range("A2").CopyFromRecordset rs
.Close
End With
' Close connection
cn.Close
Set rs = Nothing
Set Conn = Nothing
End Sub
Sub Refresh()
' Define SQL query
Dim mySQL As String
mySQL = "select a.oracle_fin_company_id || ' - ' || a.oracle_fin_company_desc as COMPANY " & _
"From hcr_dm.legal_entity_summary a " & _
"where a.Company_Header = 'Filed'"
' Choose worksheet where results should be displayed
Dim myWkSht As String
myWkSht = "Sheet1"
' Call connection sub
Call FillWithSQLData(mySQL, myWkSht)
End Sub
You're not selecting a field. The lines
Set rf = cn.Execute(sql_count)
Do While rf.Fields.Value = 8
Should probably be
Set rs = cn.Execute(sql_count)
Do While rs.Fields(0).Value = 8
Also, note the typo in that you declared rs but you're filling rf with the Recordset.
I recommend you use the Option Explicit statement to help find these. You can read more about it here.