Hi,
I am trying to import a number of CSV's from a number of folders including subfolders. The snag is that I need to record the folder name with the file contents from each folder.
I can import the file name and contents when it is from one folder, but not multiple.
I am able to import the full directory list including the folder/subfolder names but not the contents of the actual files. I have used a function from http://allenbrowne.com/ser-59alt.html fofull location for this.
If i have the full path of the files I need in a seperate table, can I use this to loop through to import the files?
I have tried everything I have found on the subject and believe I'm very close :)
Thanks all
Gareth
Not sure if you are still interested, but I do believe that I did come up with a purely based Access solution. Won't go into details unless you request them, just look at the Attached Demo.
23 4017
This will get all the file names that meet your criteria in folders and subfolders.
If you have a routine to import the data, put that in where the Debug statement goes - Sub Test()
-
-
Dim colFiles As New Collection
-
-
RecursiveDir colFiles, "E:\Phil Data\Access", "*.Csv", True
-
-
Dim vFile As Variant
-
For Each vFile In colFiles
-
Debug.Print vFile
-
Next vFile
-
-
End Sub
-
-
Public Function RecursiveDir(colFiles As Collection, _
-
strFolder As String, _
-
strFileSpec As String, _
-
bIncludeSubfolders As Boolean)
-
-
Dim strTemp As String
-
Dim colFolders As New Collection
-
Dim vFolderName As Variant
-
-
'Add files in strFolder matching strFileSpec to colFiles
-
strFolder = TrailingSlash(strFolder)
-
strTemp = Dir(strFolder & strFileSpec)
-
Do While strTemp <> vbNullString
-
colFiles.Add strFolder & strTemp
-
strTemp = Dir
-
Loop
-
-
If bIncludeSubfolders Then
-
'Fill colFolders with list of subdirectories of strFolder
-
strTemp = Dir(strFolder, vbDirectory)
-
Do While strTemp <> vbNullString
-
If (strTemp <> ".") And (strTemp <> "..") Then
-
If (GetAttr(strFolder & strTemp) And vbDirectory) <> 0 Then
-
colFolders.Add strTemp
-
End If
-
End If
-
strTemp = Dir
-
Loop
-
-
'Call RecursiveDir for each subfolder in colFolders
-
For Each vFolderName In colFolders
-
Call RecursiveDir(colFiles, strFolder & vFolderName, strFileSpec, True)
-
Next vFolderName
-
End If
-
-
End Function
-
-
Public Function TrailingSlash(strFolder As String) As String
-
' Add a backslah if it's missing
-
If Len(strFolder) > 0 Then
-
If right(strFolder, 1) = "\" Then
-
TrailingSlash = strFolder
-
Else
-
TrailingSlash = strFolder & "\"
-
End If
-
End If
-
-
End Function
Phil
AIRCODE Example: - Let's assume that you have the very simple Table Structure and Data below:
-
ID FilePath
-
1 C:\Test\File1.csv
-
2 C:\Test\File2.csv
-
3 C:\Test\File3.csv
-
- The following Code will loop thru all the *.csv File Paths contained within the [FilePath] Field, then Import the *.csv File into a Table named with the corresponding Primary Key Field ([ID]) Value.
- Dim MyDB As DAO.Database
-
Dim rst As DAO.Recordset
-
Dim intCtr As Integer
-
-
Set MyDB = CurrentDb
-
Set rst = MyDB.OpenRecordset("tblCSVFiles", dbOpenSnapshot)
-
-
With rst
-
Do While Not .EOF
-
DoCmd.TransferText acImportDelim, , ![ID], ![FilePath], True
-
.MoveNext
-
Loop
-
End With
-
-
rst.Close
-
Set rst = Nothing
- After Code Execution you will have three new Tables named 1, 2, and 3.
- The Code assumes that you have Field Names embedded in the *.csv Files.
Thanks both for replying. I tried the code from AIRCODE and I am 90% there now.I have a list of tables with the contents of the CSV's, and each table name corresponds with the ID of the path in the directory table.
I have tried and tried however to find a way of linking the table name with the ID of the directory table. Is there a way of doing this? I presume it will involve some sort of INSERT INTO query where I would insert the tablename into the corresponding table.
I have tried looking for a function to loop through all tables and add the table name to the table.
Is this possible via VBA or a function do you think?
I am even closer now. I have used the below code to append all the tables into one: - Dim db As DAO.Database
-
Dim rs As DAO.Recordset
-
-
Const cstrAppend As String = "INSERT INTO maintable SELECT * FROM "
-
-
Set db = CurrentDb()
-
Set rs = db.OpenRecordset("tableoftables")
-
-
Do Until rs.EOF
-
db.Execute cstrAppend & rs!TableName, dbFailOnError
-
rs.MoveNext
-
Loop
-
-
rs.Close: Set rs = Nothing
-
Set db = Nothing
-
I have then tried this one to do the same as the above, but append the tablename as well - Dim db As DAO.Database
-
Dim rs As DAO.Recordset
-
Dim cstrAppend As String
-
-
Set db = CurrentDb()
-
Set rs = db.OpenRecordset("tableoftables")
-
-
cstrAppend = "INSERT INTO maintable SELECT *, """ & rs!TableName & """, FROM & rs!TableName"
-
-
Do Until rs.EOF
-
-
db.Execute cstrAppend, dbFailOnError
-
rs.MoveNext
-
Loop
-
-
rs.Close: Set rs = Nothing
-
Set db = Nothing
However the second one gives me this error;
No Destination field name in INSERT INTO statement ("993")
993 is my ID above which is correct.
Any ideas?
Thanks
AFIK The Append query takes the form of
INSERT INTO MainTable (Field1, Field2.....)
SELECT FieldA, FieldB... FROM SecondTable;
So I think you need to define the corresponding fields from both tables.
As, in your case, the SecondTable is a calculated value, I think I would try
FROM Chr$(34) & rs!TableName & Chr$(34);
I have a pet hatred of """, and always use Chr$(34) which is a double quote
Phil
I have tried all ways of using Chr$(34) but cannot seem to get the syntax right. I have gone a slightly different way below and am agonisingly close now...
When I hover over the strSQL I can see
"INSERT INTO maintable select *, "993", from "993""
All the rs!tablename variables are correct. - Dim db As DAO.Database
-
Dim rs As DAO.Recordset
-
Dim cstrAppend As String
-
-
Set db = CurrentDb()
-
Set rs = db.OpenRecordset("tableoftables")
-
-
strsql = "INSERT INTO maintable SELECT *, """ & rs!TableName & """, FROM """ & rs!TableName & """"
-
Do Until rs.EOF
-
-
db.Execute strsql, dbFailOnError
-
rs.MoveNext
-
Loop
-
-
rs.Close: Set rs = Nothing
-
Set db = Nothing
I still get the error No Destination field name in INSERT INTO statement ("993")
Do i need to specify an alias in the statement? I have tried a few ways but I just get a syntax error.
Please read my previous post. You have not defined the fields specifically in the Main table that you want to append, nor defined specifically the fields that the data is coming from in your input tables.
I've tried doing this but unfortunately I keep getting syntax errors. All the fields from other tables copy across ok as they are picked up in the SELECT *. The only issue is the table name variable rs!tablename. I have added a field to the new table called "tablename" however I dont believe this makes a difference. I believe I need to specify what field to append the tablename to, but I am sure of the syntax.
Appreciate your help with this :)
Without knowing the field names in the two tables, it is difficult to be of further help. Perhaps you would enlighten us
Phil
No problem, these are all test names for now, but there is a table containing all the table names called "tableoftables" with [ID] and [tablename]
The fields in each table I am appending from has [field1] and [field2]. These copy append fine into a table called "maintable".
I have added a field called [tablename] into this "maintable" as it is the same name as the field in "tableoftables" The only issue appears to be appending the table name :(
I used my previous Code Segment to illustrate how you can utilize a Table Name and Primary Key, inserting a combination of both into a Main Table: -
Dim MyDB As DAO.Database
-
Dim rst As DAO.Recordset
-
Dim strTableName As String
-
Dim strSQL As String
-
-
strTableName = "tblCSVFiles"
-
-
Set MyDB = CurrentDb
-
Set rst = MyDB.OpenRecordset(strTableName, dbOpenSnapshot)
-
-
With rst
-
Do While Not .EOF
-
strSQL = "INSERT INTO [MainTable] ([MyID]) VALUES('" & ![ID] & "_" & strTableName & "')"
-
CurrentDb.Execute strSQL, dbFailOnError
-
.MoveNext
-
Loop
-
End With
-
-
rst.Close
-
Set rst = Nothing
Try strSQL = "INSERT INTO [MainTable] ([MyID]) SELECT ![ID] & "_" & !strTableName AS NewTable"
You certainly need an exclamation mark before strTableName
If ID is numeric, you may need Cstr(!ID)
Phil
You certainly need an exclamation mark before strTableName
Not required, it is a String Variable, not a Field Name.
If ID is numeric, you may need Cstr(!ID)
Not required, it will be coerced to a String.
We are a step closer as this now adds the table ID to the main table, however it doesnt add the contents of the other tables. Is there a way we can incorporate SELECT * from the other tables as well as appending the table name?
What I believe I need is something like - strSQL = "INSERT INTO [MainTable] SELECT *,([MyID]) VALUES('" & ![ID] & "_" & strTableName & "')"
But this doesnt work :(
Really appreciate all your help with this one.
@Gareth:
Sorry, but I am a little confused at this point. Is there any chance of you Uploading a subset of your DB, stripped of any sensitive information, along with an exact explanation of what you are looking for and what the correct results should be?
Thanks for taking the time on this. I have uploaded the DB for you to look at. The DB just contains the functions to make this work as a concept.
First I click button1 which runs the function in module 1. This imports the directory listing of the specifc folder including subfolders, which creats [tbldirectory]
Button2 then creates a new table from [tbldirectory] that combines the path and CSV file name into [tbldirectory2]. It then imports the contents of the CSVs into seperate tables. Each table name is the ID of [tbldirectory2]. (You will see these are 1011, 1012 etc)
Button3 then appends the contents of all the above tables into one [Maintable] Its at this point I need the table name of each table (1011, 1012 etc) to be appended to the maintable. This is so I know the location of each CSV. Otherwise [maintable] is just data with no reference to where it orginated from.
Let me know if you need anymore information, thanks.
I've looked at your Database and this is what I see: - You want to Append the Data in Tables 1011, 1012, 1013, 1014, 1015, and 1016 to the Table maintable.
- Tables 1011 thru 1016 consist of different Fields.
- maintable is a conglomeration of all the Field Names in Tables 1011 thru 1016.
- If the above statements are correct, then you have a difficult task ahead of you. As you Append each Table to maintable you must first synchronize the Fields to Append. A case in point would be:
Table 1011 has the following Fields which must be Appended to maintable along with the Table Name: -
[db_name]
-
[min]
-
[max]
-
[name1]
-
- Tables 1012 thru 1016 may/may not have these Fields as well as additional Fields.
I see what you mean. There may be a way of appending the table name to each table individually before appending them all together.
Something along the lines of for each table ID in tbldirectory2, append the ID to the table with the same ID. I can then combine all these into one table which I have done already. That is all I need to do TBH.
I think that it can actually be done, but I will not be able to attempt it until Friday at the earliest. I'll check back in then, and if you are still interested, I'll see what I can come up with.
I've got it :) I started from scratch and it though it may be easier to append the folder path using Excel. So the method I used to automate the whole process was to first import the folder structure into Access using button1 in the DB. Then I exported this folder structure into Excel. I then used the below code to import the content in: - Sub step1()
-
-
Dim wsMstr As Worksheet: Set wsMstr = ThisWorkbook.Sheets("sheet1")
-
-
wsMstr.UsedRange.Clear
-
-
Call step2
-
-
End Sub
-
- Sub step2()
-
-
Call Combined
-
-
End Sub
-
- Sub Combined()
-
-
If Sheets("sheet2").Range("A2") = "" Then
-
Exit Sub
-
-
Else
-
-
Call ImportCSVsWithReference
-
-
Rows("2:2").Select
-
Selection.Delete Shift:=xlUp
-
-
Call step2
-
-
End If
-
-
End Sub
- Sub ImportCSVsWithReference()
-
-
Dim wbCSV As Workbook
-
Dim wsMstr As Worksheet: Set wsMstr = ThisWorkbook.Sheets("sheet1")
-
Dim fPath As String: fPath = Sheets("sheet2").Range("A2") 'path to CSV files, include the final \
-
Dim fCSV As String
-
-
Application.ScreenUpdating = False 'speed up macro
-
-
fCSV = Dir(fPath & "*.csv") 'start the CSV file listing
-
-
Do While Len(fCSV) > 0
-
'open a CSV file
-
Set wbCSV = Workbooks.Open(fPath & fCSV)
-
'insert col A and add CSV name
-
Columns(1).Insert xlShiftToRight
-
Columns(1).SpecialCells(xlBlanks).Value = ActiveSheet.Name & fPath
-
'copy date into master sheet and close source file
-
ActiveSheet.UsedRange.Copy wsMstr.Range("A" & Rows.Count).End(xlUp).Offset(1)
-
wbCSV.Close False
-
'ready next CSV
-
fCSV = Dir
-
Loop
-
-
Application.ScreenUpdating = True
-
-
End Sub
-
I then imported the resulting 25k rows back into Access :)
Thank you all again for your help in getting this to a resolution. Really appreciate it.
Not sure if you are still interested, but I do believe that I did come up with a purely based Access solution. Won't go into details unless you request them, just look at the Attached Demo.
This is perfect. I will use your one as it does exactly what I need and does not need the steps to Excel.
Appreciate the time you took to create this. Thanks :)
Glad it all worked out for you. Just keep in mind that the Code is based on two MAJOR assumptions: - The Imported *.csv Files will always be imported into Tables whose Names are Numeric, namely: 1011, 1022, 1234, 6724, etc. No other Tables in your Database, aside from the Imported CSVs, have Names that are purely Numeric.
- All Fields in the imported Tables have exact counterparts, both in Name and Data Types, in maintable.
Sign in to post your reply or Sign up for a free account.
Similar topics
by: Mark Everett |
last post by:
Hi,
I am currently running out of space on one of my database servers. Is
it possible to move the relevant files for tables onto another drive
and instuct MySql to use both folders for it's...
|
by: Jaco Karsten |
last post by:
Hi
I am desperately looking for a way to select multiple
folders from an explorer type TreeView like the one used
with the Windows backup utility. I would like to offer
the user the ability to...
|
by: Harley |
last post by:
i have an application that uses forms security to restrict access to a
specific folder. now i need to secure another folder, in the same root, but
redirect those users to another login. imagine,...
|
by: Pete |
last post by:
I need to import multiple tab delimited files for which I do not have
the formats. All files have column headers in the the line. The
files must be dynamic. The only common value is that the...
|
by: D2 |
last post by:
Hi All,
I'm just wondering whether a FileSystemWatcher object can be used to
monitor multiple directores or we have to create one FileSystemWatcher
object for each folder we need to monitor?
...
|
by: ink |
last post by:
Hi all,
My company does things in a very specific way. Meaning we never query the
database directly, we always use Stored Procedures.
What i would like is to develop one data provider class...
|
by: andrewwan1980 |
last post by:
I am an ASP web developer developing a website.
I've got ASP files in many sub-folders of many levels deep.
I've always used:
<!-- #INCLUDE...
|
by: moijes12 |
last post by:
Hi friends
I have a module "bigbee" in folder C:\MyDocs\BigBee and another module
"foo" needs to import from this.however, "foo" is in D:\foo.
foo.py :
from bigbee import *
The error i...
|
by: komk |
last post by:
Unzip multiple folder through For loop using ANT script
|
by: lllomh |
last post by:
Define the method first
this.state = {
buttonBackgroundColor: 'green',
isBlinking: false, // A new status is added to identify whether the button is blinking or not
}
autoStart=()=>{
|
by: DJRhino |
last post by:
Was curious if anyone else was having this same issue or not....
I was just Up/Down graded to windows 11 and now my access combo boxes are not acting right. With win 10 I could start typing...
|
by: isladogs |
last post by:
The next Access Europe meeting will be on Wednesday 4 Oct 2023 starting at 18:00 UK time (6PM UTC+1) and finishing at about 19:15 (7.15PM)
The start time is equivalent to 19:00 (7PM) in Central...
|
by: tracyyun |
last post by:
Hello everyone,
I have a question and would like some advice on network connectivity. I have one computer connected to my router via WiFi, but I have two other computers that I want to be able to...
|
by: NeoPa |
last post by:
Hello everyone.
I find myself stuck trying to find the VBA way to get Access to create a PDF of the currently-selected (and open) object (Form or Report).
I know it can be done by selecting :...
|
by: Teri B |
last post by:
Hi, I have created a sub-form Roles. In my course form the user selects the roles assigned to the course.
0ne-to-many. One course many roles.
Then I created a report based on the Course form and...
|
by: isladogs |
last post by:
The next Access Europe meeting will be on Wednesday 1 Nov 2023 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM)
Please note that the UK and Europe revert to winter time on...
|
by: nia12 |
last post by:
Hi there,
I am very new to Access so apologies if any of this is obvious/not clear.
I am creating a data collection tool for health care employees to complete. It consists of a number of...
|
by: NeoPa |
last post by:
Introduction
For this article I'll be focusing on the Report (clsReport) class. This simply handles making the calling Form invisible until all of the Reports opened by it have been closed, when it...
| |