Ms access Merge Multiple Access file tables - vba

I have 60 MS Access files with the same database structure. I want to take data from two tables which are in relation from each database to make one single database with all of the records from those 60 files. Is there any easy way to merge all those MS Access files?

If I understand you correctly, you have identical tables spread across 60 database files, and you are looking at a way of automating their aggregation.
There's a few different ways you can do this. It'll probably depend on your circumstances. I've demonstrated two different approaches.
The first method is straightforward. It simply builds a static query, substituting the database name into each query. If your specifics are simplistic - then this should do the trick.
The second method uses DAO to open each table in each database and write the data to the current database. This method is beneficial if you have one-off exceptions and need to add some intelligence.
Public Sub SimpleCombine()
Dim DBFileList As Collection
Dim DBPath As String
Dim ForeignTableName As String
Dim LocalTableName As String
Dim dbfile As Variant
' Configure
Set DBFileList = New Collection
DBFileList.Add "Test1.accdb"
DBFileList.Add "Test2.accdb"
DBPath = CurrentProject.Path ' (No Trailing Backslash)
ForeignTableName = "Fruit"
LocalTableName = "Fruit"
For Each dbfile In DBFileList
querystr = "INSERT INTO Fruit (FruitName, FruitValue) " & _
"SELECT FruitName, FruitValue " & _
"FROM Fruit IN '" & DBPath & "\" & dbfile & "'"
Debug.Print "Transferring Data From " & dbfile
CurrentDb.Execute querystr
DoEvents
Next
End Sub
Example #2
Public Sub DAOCombine()
Dim DBFileList As Collection
Dim DBPath As String
Dim ForeignTableName As String
Dim LocalTableName As String
Dim db As DAO.Database
Dim rst, drst As DAO.Recordset
Dim fld As DAO.Field
' Configure
Set DBFileList = New Collection
DBFileList.Add "Test1.accdb"
DBFileList.Add "Test2.accdb"
DBPath = CurrentProject.Path ' (No Trailing Backslash)
ForeignTableName = "Fruit"
LocalTableName = "Fruit"
Set drst = CurrentDb.OpenRecordset(LocalTableName)
For Each dbfile In DBFileList
Debug.Print "Transferring Data From " & dbfile
Set db = DBEngine.Workspaces(0).OpenDatabase(DBPath & "\" & dbfile)
Set rst = db.OpenRecordset(ForeignTableName)
Do Until rst.EOF
drst.AddNew
For Each fld In rst.Fields
If (fld.Attributes And dbAutoIncrField) = dbAutoIncrField Then
' We have an autonumber field - lets skip
Else
drst.Fields(fld.Name).Value = fld.Value
End If
Next
drst.Update
rst.MoveNext
Loop
rst.Close
DoEvents
Next
drst.Close
Set rst = Nothing
Set drst = Nothing
End Sub
You'll need to tailor the code to your specific circumstances - but it should do the trick.

If the datastructure is the same you can use a JOIN
Query.
SELECT PORDER_ARV.*
FROM PORDER_ARV
UNION
SELECT PORDER_RAN.*
FROM PORDER_RAN
UNION
SELECT PORDER_HOL.*
FROM PORDER_HOL
UNION SELECT PORDER_HIN.*
FROM PORDER_HIN
ORDER BY PURCHASE_CODE;
When you use Union All ,you will also get duplicates, you can write vba code to auto construct this sql string with your 60 table names. I don't no if the union function works with 60 tables?

Related

Replace Special Chars at Attr Level

My app receives third party data.
How can I replace special characters at the column level?
I am mostly concerned about (') and (") (Char 34 & Char 39), but would like to handle anything outside the normal a-z, A-Z, 0-9 character sets.
There are 6-10 attrs for which I would apply this type of replace().
Simplest form:
Public Function new_RemoveSpecialChars(strAttr) As String
Dim db As Database
Dim strSQL As String
Set db = CurrentDb
strSQL = "UPDATE MatchedTb " & _
"SET MatchedTb." & strAttr & " = Replace(Nz([" & strAttr & "]),Chr(39),Chr(39) & Chr(39));"
db.Execute strSQL
End Function
Can I concatenate many compare/replace strings?
Is there a better, more efficient approach?
Is the data a external file? (say csv, xml etc).
I would pre-process the file BEFORE you import the data. And you can well do that pre-processing the data from Access. So, I recommend you open the data file - process the data, save the file. You THEN import the file.
#Edit
Since you have to process the data after import?
I recommend you process the data like this:
Dim sFields As String
Dim sField As Variant
Dim rstData As DAO.Recordset
Dim strSql As String
sFields = "City,Address,CompanyName"
sField = Split(sFields, ",")
Dim sF As Variant
Dim strFromChar As String
strFromChar = Chr(40)
Dim strToChar As String
strToChar = Chr(39)
strSql = "select * from MatchedTb"
Set rstData = CurrentDb.OpenRecordset(strSql)
Do While rstData.EOF = False
rstData.Edit
For Each sF In sField
If Nz(rstData(sF), "") <> "" Then
rstData(sF) = Replace(rstData(sF), strFromChar, strToChar)
End If
Next sF
rstData.Update
rstData.MoveNext
Loop
rstData.Close
So using a recordset will eliminate the need to concatenate strings, and also allows you to skip/test for a null and not process.

How to insert data from Excel into a database

I'm looking for a solution to import data from an Excel file into a database (for example: MS Access file).
I can get the idea as well as the structure but because I'm new to something like this it is really hard to finish the work.
Below is my code, which should do these:
Select database
Select import files
Create connection using ADODB
I'm stuck here, using Insert statement to import but how? Because the values to import would be a value of a variable run from the very first cell of Excel files till the end of it.
Please ignore the comment because I'm using my native language to easier understand in future
Sub Import_Data()
'Khai bao bien lien quan den Database
Dim connection As ADODB.connection
Dim record As ADODB.Recordset
'Khai bao cau lenh Query
Dim SQLstr As String
'Khai bao connection string
Dim connectionstring As String
Dim dbstring As String
'Duong dan den file import
Dim fdlg As FileDialog
Application.ScreenUpdating = False
'Chon datafile
With Application.FileDialog(msoFileDialogFilePicker)
.AllowMultiSelect = False
.Filters.Clear
.Filters.Add "Access files", "*.accdb, *.mdb"
If .Show = True Then
datapath = .SelectedItems(1)
Else
Exit Sub
End If
End With
'Chon file import
Set fdlg = Application.FileDialog(msoFileDialogFilePicker)
With fdlg
.AllowMultiSelect = False
.Filters.Clear
.Filters.Add "Excel files", "*.xls,*.xlsx,*.xlsm"
If .Show = True Then
importstring = .SelectedItems(1)
Else
Exit Sub
End If
End With
'Connect to Database
Set connection = New ADODB.connection
With connection
.Provider = "Microsoft.ACE.OLEDB.12.0"
.connectionstring = "Data Source=" & datapath & ";"
.ConnectionTimeout = 30
.Open
If .State = adStateOpen Then
MsgBox "welcome " & Environ("Username") & " ket noi den database"
Else: Exit Sub
End If
End With
Dim a, c As Integer
Dim b, d As Integer
Dim ImpWb As Workbook
Dim ImpWs As Worksheet
Set ImpWb = Application.Workbooks.Open(importstring)
ImpWb.Application.Visible = True
Set ImpWs = ImpWb.Worksheets("Sheet1")
With ImpWs.UsedRange
a = .Rows.Count
b = .Columns.Count
For c = 2 To a
For d = 1 To b
SQLstr = "Insert into Test values(" & Cells(c, d).Value & ")"
connection.Execute SQLstr
Next d
Next c
End With
ImpWb.Close
connection.Close
Set ImpWs = Nothing
Set ImpWb = Nothing
Set connection = Nothing
End Sub
From the comments above it's become clearer now that the issue you face is how to build the SQL statements inside VBA. However, you are very much closer than you think.
This function below will build an insert statement for each row of data provided the columns in the Excel tab is exactly equal to and in exact order as the fields in the SQL table. It also will combine all the inserts into one statement so you can execute all the rows at once.
With ImpWs.UsedRange
a = .Rows.Count
b = .Columns.Count
For c = 2 To a
SQLstr = SQLstr & "INSERT INTO TEST VALUES("
For d = 1 To b
SQLstr = SQLStr & .Cells(c, d).Value & iif(d <> b, ",","")
Next d
SQLstr = SQLStr & ");"
Next c
End With
The other caveat is that assumes all fields are numerical. If you have some text fields you will have to add ' before and after each field, like ' & .Cells(c, d).Value & & '. If you know the columns that need text, you can modify the input with a Select Case on column number as needed.
Hi you recognize or discovered already the magic connection.execute function. Here is the music playing. All its need is a valid SQL string to insert. That's (nearly) all.
SQL Strings can be fired single by single or a bunch separated by a ";" at the end
INSERT INTO table1 (column1,column2 ,..)
VALUES
(value1,value2 ,...),
(value1,value2 ,...),
...
(value1,value2 ,...); --<<<<<<<<<<< see the ";"
In your case you has to define the affected columns in the first line and then just all the values for a line inside the braces. If this do not work - something is wrong with the SQL string. You can use access which has a nice SQL builder to create a sql template or maybe use a online sql tester to see if your sql is valid. For testing purposes i suggest to just add one line first. And another hint: The values has to be escaped ! So add first something trivial like "abc" or 1234 just to check out the principle function. Life datas might have things like this >"< inside or "," or other things which could be seen as sql statement. Which will end up like it will do nothing at all. So read the manual how access escaped such poisoned text fragments ;) And implement a function to avoid that. SQLITE has a nice tutorial and example page. SQLITE is nearly like access. To get a overview i would read there first and the M$ documentation a biut later. Have fun :)
There is also this approach using SQL
Sub test()
Dim c As ADODB.Connection
Dim s As String
Dim strSQL As String
s = "Provider=Microsoft.ACE.OLEDB.12.0;" & _
"Data Source=c:\…...\TestDBs\API_TEST.accdb;" & _
"Persist Security Info=False;"
Set c = New ADODB.Connection
c.ConnectionString = s
c.Open
' Excel workbook, sheet name test1
strSQL = "INSERT INTO tblDestination ( Firstname )" & _
"SELECT [test1$].FirstName " & _
"FROM [EXCEL 12.0;HDR=YES;IMEX=2;DATABASE=C:\Databases\csv\test1.xlsx].[test1$];"
c.Execute strSQL
c.Close
End Sub

Unable to read data from a CSV using ADO due to the driver thinking I am working with integers/number and showing nulls instead of text

I am trying to use the ADO to read in a series of text files into a worksheet. I am running into problems when the majority of the data in a specific column are integers. It will give null values (blank cells) when it reaches a String.
According to microsoft support (Ado mixed data tyes) this is a common thing and the solution is to set the IMEX = 1. I tried this however it didn't work.
I have been searching others threads looking for the answer and came across this answer (other thread) where the author says to change TypeGuessRows to "get the Jet to detect whether a mixed types situation exists and trick the Jet into detecting a certain data type." However, this hasn't worked either.
Below is my VBA code. Any help would be appreciated
Sub query_text_file(WorkingSheet As String, Col As String, Row As Integer, fileName As String, firstOrLast As Integer)
Dim strPath As String
Dim ws As Worksheet
strToolWkbk = fileName
strPath = ThisWorkbook.Path & "\Excel_Barcode_Files"
Set ws = Worksheets(WorkingSheet)
'Need to reference the:
' Microsoft ActiveX Data Objects 2.5 Library
Dim s_rst As ADODB.Recordset
Dim s_cnn As ADODB.Connection 's for sub connection
Dim intRow As Integer
Const adOpenStatic = 3
Const adLockOptimistic = 3
Const adCmdText = &H1
Set s_cnn = New ADODB.Connection
s_cnn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & strPath & ";" _
& "Extended Properties=""text;HDR=Yes;IMEX=1;TypeGuessRows=12;FMT=Delimited"";"
s_cnn.Open
Set s_rst = New ADODB.Recordset
strSQL = "SELECT * FROM " & strToolWkbk
s_rst.Open strSQL, _
s_cnn, adOpenStatic, adLockOptimistic, adCmdText
intRow = Row
s_rst.MoveFirst
Do Until s_rst.EOF
ws.Range(Col & intRow) = s_rst(0)
ws.Range(Chr(Asc(Col) + 1) & intRow) = s_rst(1)
intRow = intRow + 1
s_rst.MoveNext
Loop
s_rst.Close
s_cnn.Close
Set s_rst = Nothing
Set s_cnn = Nothing
End Sub
Here is a sample text file. The code reads in everything except the "P"
test test
P,0
1,1
5,2
6,3
Basically, don't rely on the registry entries as explained here on MSDN.
You need to create a Schema.ini file and put it in the same folder as all your text files. In the Schema.ini you specify the type for all columns you may have in your text files - it's just a much safer option to do that explicitly rather than have the driver work out the correct types for columns...
Say you have some txt files on your desktop, open Notepad and copy paste the below - make sure you adjust the [test.txt] part to match the name of your actual txt file and save it as: Schema.ini
[test.txt]
Format=CSVDelimited
Col1=Column1 Text
Col2=Column2 Text
Make sure you add another slash at the end of the parth in the strPath (also indicated in the article)
strPath = ThisWorkbook.Path & "\Excel_Barcode_Files\"
*Keep in mind that I am working in a different location to yours - I am using my Desktop for this example and my text file is named test.txt
Now, that you have a Schema.ini you can modify the connection string and take out some parameters which are not required because they exists in the Schema.ini
So bascially an SSCCE based on the above assumptions would be:
Sub Main()
Cells.ClearContents
Dim cn As New ADODB.Connection
Dim rs As New ADODB.Recordset
Dim thePath As String
thePath = "C:\Users\" & Environ("USERNAME") & "\Desktop\"
cn.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & thePath & ";" _
& "Extended Properties=""text;HDR=No;"""
cn.Open
Dim sql As String
sql = "SELECT * FROM test.txt"
' populate the recordset
rs.Open sql, cn, adOpenStatic, adLockOptimistic, &H1
' copy the recordset starting at Range("A1") - assuming there are no headers - see HDR = No;
Range("A1").CopyFromRecordset rs
rs.Close
Set rs = Nothing
cn.Close
Set cn = Nothing
End Sub
Now after running this you should see all the values including the missing P:

Data on disk is not directly updated with the 'Update' functionality on my recordset

I am working on some VBA macros. I also use ADODB.Recordset to access data in my Access database.
Now, I need to loop through records in my table and in this loop, also need to update the same table in another function.
Here is the code (cleaned for easy reading).
Dim strSql As String
Dim rstCycles As adodb.Recordset
strSql = "SELECT * FROM tblCycles WHERE DatePlanning = #" & dteCurrentDate & "#"
Set rstCycles = SelectQuery(strSql)
While Not rstCycles.EOF
if ... then
rstCycles("NoCycle1") = ...
rstCycles.Update
end if
RefreshPlanning (*)
rstCycles.MoveNext
Wend
(*) In this function I perform a select on the tblCycles table.
The problem is after the rstCycles.Update, the data is not immediately record on disk thus the call to RefreshPlanning does not read updated data. If I set a '1 second pause' after the update everything is ok. I don't want to use a kind of pause in my loop. Is there another solution?
UPDATE ---------------
RefreshPlanning is a simple function to refresh my excel sheet based on my tblCycles table.
Sub RefreshPlanning(DatePlanning As Date, CodeEquipement As String)
Dim strSql As String
Dim rstCycles As adodb.Recordset
strSql = "SELECT * FROM tblCycles WHERE DatePlanning = #" & DatePlanning & "# AND CodeEquipement = '" & CodeEquipement & "'"
Set rstCycles = SelectQuery(strSql)
While Not rstCycles.EOF
' Some code here to update my excel sheet
' ...
rstCycles.MoveNext
Wend
End Sub
DAO is many times faster than ADO with MS Access:
Dim strSql As String
Dim rstCycles As DAO.Recordset
Dim db As Database
Set db = OpenDatabase("z:\docs\test.accdb")
strSql = "SELECT * FROM tblCycles WHERE DatePlanning = #" & dteCurrentDate & "#"
Set rstCycles = db.OpenRecordset(strSql)
While Not rstCycles.EOF
if ... then
rstCycles.Edit
rstCycles("NoCycle1") = ...
rstCycles.Update
end if
''Need more information here
RefreshPlanning (*)
rstCycles.MoveNext
Wend
If dteCurrentDate is the same as today, you can say:
"SELECT * FROM tblCycles WHERE DatePlanning = Date()"

Updating Multiple Rows using .edit in vba access 2007

I hope I can ask this right.
I have a listbox on a form (access 2007) and have it set on "simple" so I can multi-select.
I am trying to update multiple columns in a table, based on the selections in the listbox. I have a few textboxes that I want to use as the information to update the table.
I have a loop that is only updating the first record in the table no matter how many items are selected.
I think I understand why it's only updating the first record from my loop but am not sure
Dim db As DAO.Database
Dim rs As DAO.Recordset
Set db = CurrentDb()
Set rs = db.OpenRecordset("Table1", dbOpenDynaset)
Dim i As Variant
For Each i In Listbox.ItemsSelected
With rs
.Edit
!Col1 = Me.Textbox1
!Col2 = Me.Textbox2
!Col3 = Me.Textbox3
.Update
End With
Next
I assume this is because I am not specifying the "where" in the loop I want my table updated, but I have no idea how to do this in this loop. I would have 3 columns in the listbox (at positions 1, 3 and 4) that all need to be included to specify which records in the table need to be updated. I have tried this as well using an sql query with DoCmd.RunSql but it seems impossible to change the focus of the ListIndex mid-query. Aplogies for my lack of knowledge I am pretty new to visual basic. Please Help
Simplified example how I would give it a try if I understood correctly:
Sub MultiSelect_Listbox()
Dim lCnt as Long
dim lID as long
dim sSQL_Update as string
dim sText_1 as String
dim sText_2 as String
dim sText_3 as String
dim bSuccess as Boolean
sText_1 = me.txt_Textbox_1
sText_2 = me.txt_Textbox_2
sText_3 = me.txt_Textbox_3
With Me.lst_Listbox
For lCnt = 1 To .ListCount
If .Selected(lCnt) Then
lID = .Column(0, lCnt - 1)
'Example update for 1 column
sSQL_Update = "UPDATE T_TABLE SET COL_TEXT_1 = '" & sText_1 & "' WHERE ID = " & lID & ";"
bSuccess = Update_Statement(sSQL_Update)
End If
Next
End With
End Sub
Public Function Update_Statement(sUpdate_Stmt) As Boolean
Dim db As Database
Set db = CurrentDb
db.Execute (sUpdate_Stmt)
Update_Statement = True
End Function