Excel, VBA, SQL - Retrieve data from another workbook / Error - sql

I want to retrieve data from a closed workbook.
My code is
fileName = "the path\test.xlsx"
With CreateObject("ADODB.Connection")
.CommandTimeout = 500
.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" _
& fileName & ";" & "Extended Properties=""Excel 12.0;HDR=YES;Readonly=true"";"
.Open
ThisWorkbooks.Worksheets("new").Range("A1").CopyFromRecordset .Execute("select * from [source$B1]")
.Close
End With
I have some error, 424:object required, object doesn't found... I think it is a syntax problem.
The purpose is to retrieve data from cells and put in the other sheet/workbook
thanks for your help

Three things:
Unless you defined "ThisWorkbooks" somewhere, I think it should be "ThisWorkbook".
Using this method, I have only ever been able to fetch ranges that contain ":" in them, so change source$B1 to source$B1:B1.
Since you only want one cell, you should turn the HDR (header) option off.
fileName = "the path\test.xlsx"
With CreateObject("ADODB.Connection")
.CommandTimeout = 500
.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" _
& fileName & ";" & "Extended Properties=""Excel 12.0;HDR=No;Readonly=true"";"
.Open
ThisWorkbook.Worksheets("new").Range("A1").CopyFromRecordset
.Execute("select * from [source$B1:B1]")
.Close
End With

Related

ACE Connection String From Excel 2010 to Itself

I am trying to use SQL in VBA to update data in an existing table in Excel (same file as vba code). This is being written with SQL queries and updating with the intent of moving the source data to a DB shortly after rollout, but there are reasons why not right now. I keep getting the error "Operation must use an updateable query." Some sources show ReadOnly in the Extended Properties and some do not; both have been tried. StatusData is a named range in the Excel file. SELECT statements using the named range are working fine using the following connection string:
DBFullName = ThisWorkbook.Path & "\" & ThisWorkbook.Name
Cnct = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source='" & DBFullName & "';" & _
"Extended Properties='Excel 12.0;HDR=Yes;IMEX=1';"
Changes from the query connection include using the "Excel 12.0 Macro" extended property and ReadOnly=0, which have been incrementally. Broken code is as follows:
Cnct = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source='" & DBFullName & "';" & _
"Extended Properties='Excel 12.0 Macro;ReadOnly=0;HDR=Yes;IMEX=1';"
Set Cn = New ADODB.Connection
Cn.Open ConnectionString:=Cnct
strSQL = "UPDATE StatusData SET Notes='ttt' WHERE [Program Category]='something' AND [Program Name]='something' AND [LN]='1' AND [SN]='101';"
Cn.Execute strSQL, RecordsAffected, adExecuteNoRecords
I had problems using IMEX so in the end I stopped using it for this purpose, this connection string has never given me problems for using ADO/ACE to connect back to the workbook (usually for a SQL GroupBy), but you might need to do some conditioning on the data before making the connection (I take the entire table into an array and loop though the fields making changes as needed, then dump back to the sheet), easy enough as its already in the same workbook of course:
Dim conn As Object
Dim sPath As String
sPath = "C:\offlinestorage\temp1.xlsx"
Set conn = CreateObject("ADODB.Connection")
With conn
.Provider = "Microsoft.ACE.OLEDB.12.0"
.ConnectionString = Format("Data Source=" & sPath & ";Extended Properties='Excel 12.0 XML;HDR=Yes';")
.Open
End With

Excel VBA SQL - multiple data sources

I have a fairly simple problem which I cannot find an answer to.
I have the following SQL:-
Select a from filea where a in (select b from fileb)
I am attempting to run this in Excel using VBA.
The problem I have is that filea is a table on an AS/400 and fileb is a table in an Excel spreadsheet. That is, two different datasources.
I can't find a way to combine the two datasources in one SQL statement.
Anybody got any bright ideas.
The below example shows how to get data from two excel workbooks within single SQL query (since I haven't got any AS/400 data source), and put result recordset to the worksheet. The code is placed in Query.xlsm:
Option Explicit
Sub SqlWhereInTest()
Dim strConnection As String
Dim strQuery As String
Dim objConnection As Object
Dim objRecordSet As Object
strConnection = _
"Provider=Microsoft.ACE.OLEDB.12.0;" & _
"User ID=Admin;" & _
"Data Source='" & ThisWorkbook.FullName & "';" & _
"Mode=Read;" & _
"Extended Properties=""Excel 12.0 Macro;"";"
strQuery = _
"SELECT * FROM [Sheet1$] " & _
"IN '" & ThisWorkbook.Path & "\Src1.xlsx' " & _
"[Excel 12.0;Provider=Microsoft.ACE.OLEDB.12.0;Mode=Read;Extended Properties='HDR=YES;'] " & _
"WHERE Country IN " & _
"(SELECT CountryFilter FROM [Sheet1$] " & _
"IN '" & ThisWorkbook.Path & "\Src2.xlsx' " & _
"[Excel 12.0;Provider=Microsoft.ACE.OLEDB.12.0;Mode=Read;Extended Properties='HDR=YES;'])"
Set objConnection = CreateObject("ADODB.Connection")
objConnection.Open strConnection
Set objRecordSet = objConnection.Execute(strQuery)
RecordSetToWorksheet Sheets(1), objRecordSet
objConnection.Close
End Sub
Sub RecordSetToWorksheet(objSheet As Worksheet, objRecordSet As Object)
Dim i As Long
With objSheet
.Cells.Delete
For i = 1 To objRecordSet.Fields.Count
.Cells(1, i).Value = objRecordSet.Fields(i - 1).Name
Next
.Cells(2, 1).CopyFromRecordset objRecordSet
.Cells.Columns.AutoFit
End With
End Sub
Also there are two workbooks as data sources in the same folder as Query.xlsm.
Src1.xlsx containing Customers:
Src2.xlsx:
The resulting worksheet is as follows:
It works on 64-bit version Excel 2013 for me. To make it compatible with .xls and Excel 2003 (where the provider ACE.OLEDB.12.0 isn't installed) you have to replace Provider=Microsoft.ACE.OLEDB.12.0; with Provider=Microsoft.Jet.OLEDB.4.0;, and also in extended properties Excel 12.0 Macro; / Excel 12.0; with Excel 8.0;. Actually data source for connection object isn't limited the only Query.xlsm file (see ThisWorkbook.FullName part within strConnection), which the code placed in. It could be another data source, compatible with one of the available providers, either file-based or server-based. Find more connection strings for your data source on http://www.connectionstrings.com/

Use Excel VBA to change the value of a cell in a closed workbook?

I currently use this function in VBA to get the value of a cell in a closed workbook. I want to use a similar process to SET the value of the cell to whatever I want, without opening the file. Is that possible?
Private Function GetValue(path, file, sheet, ref)
Dim arg As String
If Right(path, 1) <> "\" Then path = path & "\"
If Dir(path & file) = "" Then
GetValue = "File Not Found"
Exit Function
End If
arg = "'" & path & "[" & file & "]" & sheet & "'!" & _
Range(ref).Range("A1").Address(, , xlR1C1)
GetValue = ExecuteExcel4Macro(arg)
End Function
Yes you can do this using ADO as Gary commented but only if your Excel Worksheet is arranged in a Database like structure.
Meaning you have valid fields arranged in columns (with or without headers).
For example:
Now, you see that ID number 12345 have a name John John and you want to update it to John Knight.
Using ADO you can try:
Edit1: You can actually do this without using Recordset. See below update.
Sub conscious()
Dim con As ADODB.Connection
Dim sqlstr As String, datasource As String
Set con = New ADODB.Connection
datasource = "C:\Users\UserName\Desktop\TestDataBase.xlsx" 'change to suit
Dim sconnect As String
sconnect = "Provider=Microsoft.ACE.OLEDB.12.0;" & _
"Data Source=" & datasource & ";" & _
"Extended Properties=""Excel 12.0;HDR=YES"";"
With con
.Open sconnect
sqlstr = "UPDATE [Sheet1$] SET [Name] = ""John Knight"" WHERE [ID Number] = 12345"
.Execute sqlstr
.Close
End With
Set con = Nothing
End Sub
Result:
I'm not entirely sure if this is what you want but HTH.
Notes:
You need to add reference to Microsoft ActiveX Data Objects X.X Library (early bind).
But you can also do this using late bind (no reference).
Connection string used is for Excel 2007 and up.
Sheet1 is the name of the target sheet you want to update the value to.
Edit1: This is how to do it if your file have no header
First change the connection string HDR argument to NO:.
sconnect = "Provider=Microsoft.ACE.OLEDB.12.0;" & _
"Data Source=" & datasource & ";" & _
"Extended Properties=""Excel 12.0;HDR=NO"";"
Then adjust your SQL string to:
sqlstr = "UPDATE [Sheet1$] SET F2 = ""John Knight"" WHERE F1 = 12345"
So that is F1 for field 1, F2 for field 2 etc.

Update Data in Excel File From Different Excel File Using SQL

I have two Excel files, a master file and a regular file. Both files have a sheet with the same data structure (same fields, but not formatted as tables).
What I'm trying to do is use VBA to create data connections to both files, and then use SQL to update the master file with any changes in the regular file. The reason for using SQL and a data connection is to avoid opening the regular file and hopefully faster performance overall.
I'm having difficulty with the UPDATE statement, and I'm not sure I'm even going about this in the best manner. My code thus far:
Sub Main()
Dim cnn1 As New ADODB.Connection
Dim cnn2 As New ADODB.Connection
Dim rst1 As New ADODB.Recordset
Dim rst2 As New ADODB.Recordset
Dim arrData() As Variant
Dim fPath As String
With Application.FileDialog(msoFileDialogFilePicker)
.AllowMultiSelect = False
.Filters.Add "Files", "*.xls*"
.InitialFileName = ThisWorkbook.Path & "/Meeting Cuts"
.Title = "Please select the file that contains the values you'd like to import."
.Show
fPath = .SelectedItems(1)
End With
DoEvents
cnn1.Open "Provider=Microsoft.ACE.OLEDB.12.0;" & "Data Source=" & CStr(fPath) & ";" & "Extended Properties=""Excel 12.0;HDR=Yes;"";"
cnn2.Open "Provider=Microsoft.ACE.OLEDB.12.0;" & "Data Source=" & CStr(ThisWorkbook.FullName) & ";" & "Extended Properties=""Excel 12.0;HDR=Yes;"";"
rst1.Open "SELECT * FROM [Sheet1$];", cnn1, adOpenStatic, adLockReadOnly
rst2.Open "UPDATE [Account Data$]" & _
"SET Account_ID = (SELECT Account_ID FROM " & rst1.GetRows & " WHERE Empl_Name = 'Smith,John')" & _
"WHERE Empl_Name = 'Smith,John'", cnn2, adOpenStatic, adLockReadOnly
Set rst1 = Nothing
Set rst2 = Nothing
Set cnn1 = Nothing
Set cnn2 = Nothing
End Sub
When I execute the code, I get a Run-time error '13': Type Mismatch on the rst2.Open line. When I go into debug mode and try to execute that line again, I get a different error: Run-time error '3021': Either BOF or EOF is True, or the current record has been deleted. Requested operation requires a current record.
I know that I'm using GetRows improperly. Is there a way to reference the sheet (from the regular file) somehow in the UPDATE statement? If so, how would I do it?

Recordset in VB6.0

I'm retrieving Data from a Database in a record set using VB6... so while retrieving data using Select in SQL I added a column called Comments along wit it so that in the recordset, all the columns of the table+'Comments' column would be present... I don't want to(and also I cannot) update any contents in the database as i'm only 'fetching' data frm the database now...
Now when i pass the fetched data for validation, I want to fill the 'comments' Column with the respective errors if the particular row in the recordSet is erroneous).... When i do that i get an error saying "I'm not authorized to do that!!(to update the 'Comments' Column"....
Now My Question is "In what way i can solve this problem???".. I tried to replicate this recordset and there by now filling the 'comments'column (in the replicated one) which in turn showed the same error... It seems this could be because the duplicate one(recordSet) just retains the properties of the original one...
Can u any1 help how to solve this???? Any ways to replicate the recordset(without inheriting its properties something)??????
I think you are just asking how to do a disconnected recordset.
For that you just change the cursor location of the recordset.
Dim rstTest as ADODB.RecordSet
Set rstTest = New ADODB.RecordSet
With rstTest
.CursorLocation = adUseClient
.Open "your sql here", your_connection_object, adOpenStatic, adLockBatchOptimistic, adCmdText
' now disconnect it and force the local copy
.ActiveConnection = Nothing
End With
Not exactly what you are looking for, but this is how I do it:
Create a class to encapsulate the recordset ('Customer' class for 'Customer' table)
Add your Comment property to the class and not to recordset
Add a Validate method to your class. Have it write to your Comment property (I use an Errors Collection)
Read the recordset
Parse it into a "new Customer"
Validate
Check the Comment property (or the Errors Collection)
You can use the MSDataShape with its SHAPE..APPEND syntax to append a new Field to an ADO Recordset. Here's a quick example using Jet (a.k.a. MS Access):
Sub ShapeAppendField()
On Error Resume Next
Kill Environ$("temp") & "\DropMe.mdb"
On Error GoTo 0
Dim cat
Set cat = CreateObject("ADOX.Catalog")
With cat
.Create _
"Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & _
Environ$("temp") & "\DropMe.mdb"
Dim jeng
Set jeng = CreateObject("JRO.JetEngine")
jeng.RefreshCache .ActiveConnection
Set .ActiveConnection = Nothing
End With
Dim con
Set con = CreateObject("ADODB.Connection")
With con
.ConnectionString = _
"Provider=MSDataShape;" & _
"Data Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & _
Environ$("temp") & "\DropMe.mdb"
.CursorLocation = 3
.Open
.Execute _
"CREATE TABLE Test (" & _
"existing_col INTEGER NOT NULL);"
.Execute _
"INSERT INTO Test (existing_col)" & _
" VALUES (1);"
Dim rs
Set rs = CreateObject("ADODB.Recordset")
With rs
.CursorType = 2
.LockType = 4
.Source = _
"SHAPE {" & _
" SELECT existing_col" & _
" FROM Test" & _
"} APPEND NEW adInteger AS new_col"
Set .ActiveConnection = con
.Open
Set .ActiveConnection = Nothing
.Fields("new_col").value = 55
MsgBox .GetString
.Close
End With
End With
End Sub