importing table from oracle into external access database using TransferDatabase - vba

i have a bunch of large Oracle tables that need to be imported into MS Access. They each go into its own database, because they're huge. Right now i'm linking them into the database that runs the procedure and then exporting into external databases using INSERT INTO.
Horribly slow.
TransferDatabase is much faster but i don't see how i can use that for external databases.
Is there a way? Or is there a way to do this quickly using some other method? This is part of an automation, so it can't be any manual solutions, has to be VBA.
In case someone is wondering why I'm doing this - these are files that go to requestors as results of a report.

Here's one way you could do it.
Create an Access database called importfile_template.accdb that contains the following:
– a table named import_config with three fields, all ShortText(255)
odbc_connection_string
source_tablename
destination_tablename
– a module containing
Option Compare Database
Option Explicit
Public Function do_import()
Dim cdb As DAO.Database
Set cdb = CurrentDb
Dim tbd As DAO.TableDef
On Error Resume Next
Set tbd = cdb.TableDefs("import_config")
If Err.Number = 0 Then
Dim rst As DAO.Recordset
Set rst = cdb.OpenRecordset("import_config", dbOpenTable)
DoCmd.TransferDatabase acImport, "ODBC Database", "ODBC;" & rst!odbc_connection_string, _
acTable, rst!source_tablename, rst!destination_tablename
rst.Close
Set rst = Nothing
DoCmd.DeleteObject acTable, "import_config"
Set cdb = Nothing
Application.Quit
End If
End Function
– and a macro named AutoExec that simply does
RunCode (do_import())
Then in your main database you can use VBA code like this:
Sub perform_import()
Dim cdb As DAO.Database
Set cdb = CurrentDb
Dim this_filespec As String
this_filespec = CurrentProject.FullName
Dim current_folder As String
current_folder = Left(this_filespec, InStrRev(this_filespec, "\"))
Dim import_filespec As String
import_filespec = current_folder & "zzz_test.accdb" ' my test setting
' VBA project reference required:
' Windows Script Host Object Model
Dim fso As New FileSystemObject
fso.CopyFile current_folder & "importfile_template.accdb", import_filespec
Set fso = Nothing
Dim qdf As DAO.QueryDef
Set qdf = cdb.CreateQueryDef("")
qdf.SQL = _
"UPDATE [" & import_filespec & "].import_config SET " & _
"odbc_connection_string = prm_odbc, " & _
"source_tablename = prm_source, " & _
"destination_tablename = prm_destination"
qdf!prm_odbc = "DSN=mssqlLocal" '
qdf!prm_source = "ThousandRows" ' my test settings
qdf!prm_destination = "thousand_rows" '
qdf.Execute dbFailOnError
qdf.Close
Set qdf = Nothing
Set cdb = Nothing
Dim wsh As New WshShell
wsh.Run import_filespec
Set wsh = Nothing
End Sub
Note: When opening importfile_template.accdb from within Access be sure to hold down the Shift key to prevent the AutoExec macro from running.

Related

1 Access Query to Multiple Excel Files Based on Field Value

I was looking for the exact same thing as the person that posted the following question:
1 MS Access Query to Multiple Excel Files Based on Field Value
This answer:
Dim Db As DAO.Database, qdef AS DAO.QueryDef, rst As DAO.Recordset
Set db = CurrentDb
Set rst = db.OpenRecordset("SELECT DISTINCT [CustomerName] FROM [QueryName]")
Do While Not rst.EOF
Set qdef = db.QueryDefs("[MyTempQuery]")
qdef.SQL = "SELECT * FROM [QueryName] WHERE Customer = '" & rst!CustomerName & "'"
Set qdef = Nothing
DoCmd.TransferSpreadsheet acExport, acSpreadsheetTypeExcel12Xml, "MyTempQuery", _
"C:\Path\To\Excel\Files\" & rst!CustomerName & ".xlsx", True
rst.MoveNext
Loop
rst.Close
Set rst = Nothing: Set db = Nothing
...provided by #Parfait worked wonders, but since this access file is going to be used by several other people i now need the access to export the files in a sub folder of the same folder as the Access file instead of specifying an exact folder path in the code. Can anyone help me with that please?
Thank you all in advance!
I am not sure if I got your question right. Do you mean:
a) The Macro has multiple users and the regarding DB is located on a shared drive:
--> if that is the case: just change "C:\Path\To\Excel\Files" to whatever is the path to the shared drive.
b) if there is no shared drive and the the macro happens to be used locally: use "C:\Temp" as path. This folder exists on every Windows machine. With that you can be sure the path is found and the files can be saved.
I found out the solution to this. Basically i declared a variable as a string, and then used that variable to store the location of the access file. Then i created a folder inside that location and used it as the export target.
Dim Db As DAO.Database, qdef AS DAO.QueryDef, rst As DAO.Recordset, expPath As String
Set db = CurrentDb
Set rst = db.OpenRecordset("SELECT DISTINCT [CustomerName] FROM [QueryName]")
expPath = Left(CurrentDb.Name, Len(CurrentDb.Name) - Len(Dir(CurrentDb.Name)))
MkDir expPath & "EXPORT"
Do While Not rst.EOF
Set qdef = db.QueryDefs("[MyTempQuery]")
qdef.SQL = "SELECT * FROM [QueryName] WHERE Customer = '" & rst!CustomerName & "'"
Set qdef = Nothing
DoCmd.TransferSpreadsheet acExport, acSpreadsheetTypeExcel12Xml, "MyTempQuery", _
expPath & "EXPORT\" & rst!CustomerName & ".xlsx", True
rst.MoveNext
Loop
rst.Close
Set rst = Nothing: Set db = Nothing

Access VBA loop to export Excel files

I have some code that I copied and modified from Export Query in VBA loop to select data based on String Value
The code works although the problem is that when it runs it creates a query in the database which is then deleted at the end. If the code breaks half way through, this query is still in the database. So when the code is run again it gives an error message saying it can't create the query as it already exists.
The query that is created within the database is named "Select * from SalesData"
The objective is that I have a query called "SalesData" which includes sales information for a number of countries. I want to export all the data for each country into an Excel file in a loop without creating any additional Access objects. Is it possible to just filter the existing query within the VBA without creating the temporary object?
Can anyone suggest any modifications to the below code to achieve this?
Sub TEST()
Dim db As DAO.Database
Set db = CurrentDb()
Dim rs1 As DAO.Recordset
Set rs1 = db.OpenRecordset("Select Distinct Country From SalesData")
Dim v As String
Dim strQry As String
Dim qdfTemp As DAO.QueryDef
Dim strQDF As String
strQDF = "select * from SalesData"
Do While Not rs1.EOF
v = rs1.Fields(0).Value
strQry = "SELECT * FROM SalesData WHERE Country = '" & v & "'"
Set qdfTemp = CurrentDb.CreateQueryDef(strQDF, strQry)
qdfTemp.Close
Set qdfTemp = Nothing
DoCmd.TransferSpreadsheet acExport, acSpreadsheetTypeExcel12Xml, _
strQDF, "C:\Users\me\Desktop\VBA_TEST\" & v & ".xlsx", True
CurrentDb.QueryDefs.Delete strQDF
rs1.MoveNext
Loop
rs1.Close
End Sub
As far as I'm aware, it would not be possible to use the TransferSpreadsheet method to extract a parameterised version of your SalesData query without either modifying the SQL of the SalesData query itself or using an additional query with selection criteria applied to the data returned by SalesData.
However, you needn't delete & recreate such query with every iteration of the loop - instead, simply modify the SQL property of the query, e.g.:
Sub test()
Dim qry As String: qry = "salesdata_temp"
Dim sql As String: sql = "select * from salesdata where country = '{0}'"
Dim out As String: out = "C:\Users\me\Desktop\VBA_TEST\"
Dim dbs As DAO.Database
Dim qdf As DAO.QueryDef
On Error Resume Next
DoCmd.DeleteObject acQuery, qry
On Error GoTo error_handler
Set dbs = CurrentDb
Set qdf = dbs.CreateQueryDef(qry, sql)
With dbs.OpenRecordset("select distinct country from salesdata")
If Not .EOF Then
.MoveFirst
Do Until .EOF
qdf.sql = Replace(sql, "{0}", !country)
DoCmd.TransferSpreadsheet acExport, , qry, out & !country & ".xlsx", True
.MoveNext
Loop
End If
.Close
End With
exit_sub:
On Error Resume Next
DoCmd.DeleteObject acQuery, qry
Exit Sub
error_handler:
MsgBox "Error " & Err.Number & ": " & Err.Description, vbExclamation + vbOKOnly, "Error"
Resume exit_sub
End Sub
Thanks to the input here, it seems that the only way to do it is to manipulate an existing query in the database or to create a query in the VBA script and then delete it at the end.
See below for an example of the first approach, the code uses a query already in the database called "blankquery".
Sub TEST()
Dim db As DAO.Database
Set db = CurrentDb()
Dim rs1 As DAO.Recordset
Set rs1 = db.OpenRecordset("Select Distinct Country From SalesData")
Dim qdfTemp As DAO.QueryDef
Dim v As String
Dim strQry As String
Dim strQDF As String
strQDF = "blankquery"
Do While Not rs1.EOF
v = rs1.Fields(0).Value
strQry = "SELECT * FROM SalesData WHERE Country = '" & v & "'"
db.QueryDefs(strQDF).sql = strQry
DoCmd.TransferSpreadsheet acExport, acSpreadsheetTypeExcel12Xml, _
strQDF, "C:\Users\me\Desktop\VBA_TEST\" & v & ".xlsx", True
rs1.MoveNext
Loop
rs1.Close
End Sub

Read CSV/Excel file into array

I am trying to make a macro which copies emails when I receive them, and saves them in specific windows folders on a network drive based on the domain name.
The list of domains I have will be large and subject to change by users without coding experience, so I am looking to develop a text, CSV, or excel file that someone can update which lists my company's relationship to them (client, vendor, sub-contractor, etc...) and their name (both of which controls the file path), the domain name (#example.com).
I think I can figure out how to do most of that (a clever combination of nested if and for statements), but I can't figure out how to read the file into an array, and my google-fu has failed me.
I don't think it really helps, but here is the code that I shamelessly copied from the web and am planning to work off of.
Option Explicit
Private WithEvents InboxItems As Outlook.Items
Sub Application_Startup()
Dim xNameSpace As Outlook.NameSpace
Set xNameSpace = Outlook.Application.Session
Set InboxItems = xNameSpace.GetDefaultFolder(olFolderInbox).Items
End Sub
Private Sub InboxItems_ItemAdd(ByVal objItem As Object)
Dim FSO
Dim xMailItem As Outlook.MailItem
Dim xFilePath As String
Dim xRegEx
Dim xFileName As String
Dim SenderAddress As String
On Error Resume Next
' Define SenderAddress as sender's email address or domain
xFilePath = PathCreator(SenderAddress)
Set FSO = CreateObject("Scripting.FileSystemObject")
If FSO.FolderExists(xFilePath) = False Then
FSO.CreateFolder (xFilePath)
End If
Set xRegEx = CreateObject("vbscript.regexp")
xRegEx.Global = True
xRegEx.IgnoreCase = False
xRegEx.Pattern = "\||\/|\<|\>|""|:|\*|\\|\?"
If objItem.Class = olMail Then
Set xMailItem = objItem
xFileName = xRegEx.Replace(xMailItem.Subject, "")
xMailItem.SaveAs xFilePath & "\" & xFileName & ".html", olHTML
End If
Exit Sub
End Sub
Function PathCreator(SenderAddress)
' [needs to read the file and create the path based on the values]
End Function
You can use ADODB to connect to the source file, and read it into a 2-dimensional array. Add a reference to Microsoft ActiveX Data Objects from Tools -> References.... For example, if you want to use an Excel file:
Dim excelPath As String
excelPath = "C:\path\to\excel\file.xlsx" ' Replace with the path to the Excel file
Dim connectionString As String
connectionString = _
"Provider=Microsoft.ACE.OLEDB.12.0;" & _
"Data Source=""" & excelPath & """;" & _
"Extended Properties=""Excel 12.0;HDR=Yes"""
'This assumes the Excel file contains column headers -- HDR=Yes
Dim sql As String
sql = "SELECT Relationship, LastName, FirstName, DomainName FROM [Sheet1$]"
'Assumes the relevant worksheet is named Sheet1
'Also assumes the first row of the sheet has the following labels: Relationship, LastName, FirstName, Domain (in no particular order)
Dim rs As New ADODB.Recordset
rs.Open sql, connectionString
Dim arr As Variant
arr = rs.GetRows 'Puts the data from the recordset into an array
rs.Close
Set rs = Nothing
Dim row As Variant, column As Variant
For row = 0 To UBound(arr, 2)
For column = 0 To UBound(arr, 1)
Debug.Print arr(column, row)
Next
Next
Using a text file or CSV is just a matter of slightly changing the connection string and the SQL. But I think using an Excel file will force the users to keep the data in columns, where in a CSV users would have to insert field- and row-separators manually; the same for any other text format -- users would have to remember the format's rules and apply them correctly.
But I question if an array is the best data structure for you to use; in this case you could use the recordset directly. In order to make sure the file is not held open, you could use a disconnected recordset. (If your intention is to find the appropriate domain name and use that to get other details, then I would suggest you load the data from a recordset into a Scripting.Dictionary.)
Also note that you probably only need to load the data from the file once, unless you expect it to change while the code is running.
I would write something like this
Dim rs As ADODB.Recordset
Function PathCreator(SenderAddress) As String
If rs Is Nothing Then
Dim excelPath As String
excelPath = "C:\path\to\excel\file.xlsx" ' Replace with the path to the Excel file
Dim connectionString As String
connectionString = _
"Provider=Microsoft.ACE.OLEDB.12.0;" & _
"Data Source=""" & excelPath & """;" & _
"Extended Properties=""Excel 12.0;HDR=Yes"""
Dim sql As String
sql = "SELECT Relationship, LastName, FirstName, DomainName FROM [Sheet1$]"
Set rs As New ADODB.Recordset
rs.CursorLocation = adUseClient
rs.CursorType = adOpenStatic
rs.Open sql, connectionString, adOpenStatic, adLockBatchOptimistic
'Disconnect the recordset
rs.ActiveConnection = Nothing
'Now the data will still be available as long as the code is running
'But the connection to the Excel file will be closed
End If
'build the path here, using the recordset fields
PathCreator = rs!Relationship & "_" & rs!LastName & "_" & rs!FirstName & "_" & rs!Domain
End Function
NB. By the same token, you can add a reference to Microsoft Scripting Runtime; then you can write the code that uses the FileSystemObject as follows:
Dim FSO As New Scripting.FileSystemObject
If Not FSO.FolderExists(xFilePath) Then
FSO.CreateFolder xFilePath
End If
and with a reference to the Microsoft VBScript Regular Expressions 5.5 libary:
Set xRegEx As New VBScript_RegExp_55.RegExp
xRegEx.Global = True
xRegEx.IgnoreCase = False
xRegEx.Pattern = "\||\/|\<|\>|""|:|\*|\\|\?"
If objItem.Class = olMail Then
Set xMailItem = objItem
xFileName = xRegEx.Replace(xMailItem.Subject, "")
xMailItem.SaveAs xFilePath & "\" & xFileName & ".html", olHTML
End If

VBA DAO Accessing Excel 2010 like database

I am trying to use DAO to write some VBA into Excel 2010. I want to be able to access an excel 2010 workbook like a database. I am trying to open a workbook instead of a mdb file. Is there any way I can use DAO with an excel workbook instead of an actual database?
Dim db As Database
Dim rst As Recordset
Dim SQL As String
SQL = "SELECT * From [DataSheet$]"
Set db = OpenDatabase(ThisWorkbook.FullName)
Set rst = db.OpenRecordset(SQL)
'displays the first record and first field
MsgBox rst.Fields(0)
'close the objects
rst.Close
db.Close
'destroy the variables
Set rst = Nothing
Set db = Nothing
I borrowed code from here http://www.excel-spreadsheet.com/vba/dao_ado.htm
Actually, you can connect to Excel workbooks using DAO by extending the arguments of DAO.OpenDatabase():
Dim conn As Object, db As Object, rst As Object
Set conn = CreateObject("DAO.DBEngine.120")
' EXCEL OLDER VERSION
Set db = conn.OpenDatabase("C:\Path\To\Excel_Workbook.xls", False, True, "Excel 8.0;HDR=Yes;")
' EXCEL CURRENT VERSION
Set db = conn.OpenDatabase("C:\Path\To\Excel_Workbook.xlsx", False, True, "Excel 12.0 Xml;HDR=Yes;")
Set rst = db.OpenRecordset("SELECT * FROM [SheetName$]")
MsgBox rst.Fields(0)
rst.Close
db.Close
Set db = Nothing
Set conn = Nothing
Set rst = Nothing
I figured out my issue. Using the code below you can access an excel file and treat it like a database.
Option Explicit
Private Sub btnConnect_Click()
Dim dataConection As New ADODB.Connection
Dim mrs As New ADODB.Recordset
Dim SQL As String
Dim DBPath As String
Dim connectionString As String
DBPath = ThisWorkbook.FullName 'Refering the sameworkbook as Data Source
'You can provide the full path of your external file as shown below
connectionString = "Provider=MSDASQL.1;DSN=Excel Files;DBQ=" & DBPath & ";HDR=Yes';"
'Open connection
dataConection.Open connectionString
'Create SQL query
SQL = "SELECT * From [DataSheet$]"
'Open record set (query or table, connection)
mrs.Open SQL, dataConection
Do While Not mrs.EOF
Debug.Print " " & mrs!Name
mrs.MoveNext
Loop
mrs.Close
'Close Connection
dataConection.Close
End Sub

Excel automation error when running SQL update statement

I have the following code that is intended to update an Access database however when i run the macro i get an automation error. If i execute the SELECT statement, it runs fine. I don't need to select any values from the worksheet to update the database.
Private Sub UpdateRecord()
ThisWorkbook.Activate
Dim cn As Object
Dim rs As Object
Dim strSql As String
Dim strConnection As String
Set cn = CreateObject("ADODB.Connection")
strConnection = "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=C:\temp\test.mdb"
strSql = "UPDATE table1 SET Name1='Test' WHERE Object_ID=2076;"
'strSql = "SELECT * FROM table1;"
cn.Open strConnection
Set rs = cn.Execute(strSql)
Worksheets("Sheet1").Select
Sheets("Sheet1").Range("A6").CopyFromRecordset rs
rs.Close
Set rs = Nothing
cn.Close
Set cn = Nothing
End Sub
Unfortunately I cannot repeat your situation and use ADODB. I recommend you to use native DAO library to work with MSJet (Access) database.
Sub qwe()
Dim dbe As New DAO.DBEngine
Dim dbs As DAO.Database
Dim rst As DAO.Recordset
Set dbs = dbe.OpenDatabase("C:\Users\nmaksudov\Documents\Database2.accdb")
dbs.Execute("UPDATE Table1 SET Field2='zzz' WHERE Field1=2")
Set rst = dbs.OpenRecordset("select * from Table1")
While Not rst.EOF
MsgBox rst.Fields(1).Value & "," & rst.Fields(2).Value
rst.MoveNext
Wend
MsgBox rst.RecordCount
End Sub
This should work perfect. Just add DAO library of correct version to your project. To find correct library open VBA editor in Access and choose Tools/References… menu. Find data access library in the list (in my case it is «Microsoft Office 12.0 Access database engine Object Library» or it could be «DAO 3.6» etc. Depens on version). After that open the same dialog in Excel and add the the object library.