Create queries in Access that link to data automatically Ms Access Gurus

Do you like this? Say thank you with a donation.

Loop, Link CSV, Document

This free tool with open source code uses VBA in an Access database to link to a batch of CSV files with queries.

As the process runs, it documents what's being done, and records information about each file along with its corresponding query name in Access. Each query's record count is calculated and stored, as well as each query field name and data type.

There are tables in the database for documentation. A report is already designed to show information from the tables.

There's a menu form that opens on startup. The first step is to browse to a folder. Set any options you want to change and run. A loop goes through the files (in subfolders too, if desired) and if a file name matches a pattern (such as *.csv), file information is obtained and it's linked using a query. Names are fixed, file problems are corrected, structure is documented, and statistics are calculated.

This gives you an easy way to look at a batch of data and see what you want you want to do with it. You don't need to import data to look at it or to shuffle it around. Linking avoids unnecessary bloating of the database caused by importing.

You can quickly see what each CSV file contains by opening a query. Run a report to see statistics and the data structure of each query.

Information is stored in tables so you can write custom VBA code to append and update tables based on what this tool tells you.

In the download section, you can also get the database from my recent Access Lunchtime presentation. It's cruder in capabilities than the current version, but has VBA you can pattern after that imports data using append and update queries.

CSV = Comma-Separated Values stored in text files.

Loop through folders, Link to CSV files using queries, Document structure and get statistics

Quick Jump

VBA modules

  1. f_MENU_LoopLinkDocument
  2. r_Documentation
  3. mod_CorrectName_s4p
  4. mod_File_LoopLinkCsvDocument_Scripting_s4p it
  5. mod_File_RemoveUTF8bom_s4p
  6. mod_GetQuery_LinkFile_s4p
  7. mod_GetSQL_LinkCsv_s4p
  8. mod_Office_GetFolder_GetFile_s4p
  9. mod_Query_Make_s4p

Goto Top  


Download

Database for this web page

This zipped ACCDB file and a folder containing sample DATA: LoopLinkDocument_s4p__ACCDB_DATA.zip

Database and PDF from my Loop and Link CSV presentation for Access Lunchtime with Maria Barnes:

The application I demonstrated has cruder capabilities than the nicer download above for this page, but it includes an example to construct update and append queries in VBA and keep track of how many records are added and changed.

Lunchtime zipped ACCDB file and a folder containing sample DATA: LoopLink_CSV_s4p.zip

Lunchtime PDF file with presentation slides Presentation_LoopLinkCSV_s4p.pdf

Remember to UNBLOCK files you download to remove the Mark of the Web. Here are steps to do that: https://msaccessgurus.com/MOTW_Unblock.htm

Goto Top  

Try it yourself

The ACCDB database contains a form with a Browse button to pick a folder. Optionally choose to read files in subfolders too. Specify a pattern for matching filenames. Run the VBA code to Loop, Link, and Document.

Currently, any file that doesn't have a TXT or CSV file extension is skipped. Files must have a header row with field names, and data must be delimited with comma. It doesn't matter if text has quote marks around it or not.

The code could be modified for other parameters and file types (such as Excel).

After running, queries are created or updated to link.

Documentation is stored in the tPath, tFile, and tField tables. There is a report.

Goto Top  

Video

Presentation to Access Lunchtime. The presentation database is less-featured than the database on this page.

watch on YouTube: AL: Loop and Link CSV Files in Access using Queries (54:51)

Goto Top  

VBA

Code behind menu form, f_MENU_LoopLinkDocument

Access main menu to browse to a folder and link to CSV files

Specify path to folder, whether looping will be recursive (include subfolders) and pattern to match filenames.

Calls code in modules:

Option Compare Database 
Option Explicit 

' cbf: f_MENU_LoopLinkDocument
'*************** Code Start ***************************************************
' Purpose  : code behind menu form to Loop, Link, and Document
' Author   : crystal (strive4peace)
' Code List: https://msaccessgurus.com/code.htm
' This tool: https://msaccessgurus.com/tool/LoopLinkDocument.htm
' LICENSE  :
'   You may freely use and share this code, but not sell it.
'   Keep attribution. Mark your changes. Use at your own risk.
'--------------------------------------------------------------------------------
'                              #Const IsEarly
'--------------------------------------------------------------------------------
#Const IsEarly = gIsEarly 
'--------------------------------------------------------------------------------
'                              Form_Load
'--------------------------------------------------------------------------------
Private Sub Form_Load() 
'230302
   Me.txtFolder = CurrentProject.Path &  "\Data"
End Sub 
'--------------------------------------------------------------------------------
'                              Form_Close
'--------------------------------------------------------------------------------
Private Sub Form_Close() 
'230204 s4p
   Call ReleaseLoopLink 
End Sub 
'--------------------------------------------------------------------------------
'                              cmd_Browse_Click
'--------------------------------------------------------------------------------

Private Sub cmd_Browse_Click() 
'230121 strive4peace
   ' CALLs
   '     mod_Office_GetFolder_GetFile_s4p
   '  GetFolder
   
   'folder path, number of files
   Dim sFolder As String 
   
   'Title of dialog box
   Dim sTitle As String 
   sTitle =  "Select the Folder to loop and link to files in"
   
   ' Call GetFolder
   sFolder = GetFolder(sTitle) 
   If sFolder =  "" Then Exit Sub 
   
   With Me 
      'folder path
      .txtFolder = sFolder 
   End With 

End Sub 

'--------------------------------------------------------------------------------
'                              cmdLoopLink_Click
'--------------------------------------------------------------------------------
Private Sub cmdLoopLinkDocument_Click() 
'230127 s4p ... 230206, 230227, 230301

   ' CALLs
   '     mod_File_LoopLinkCsvDocument_Scripting_s4p
   '  StartCountLoopLink
   '  LoopLinkPattern_s4p
   '  ReleaseLoopLink
   '     mod_Query_Make_s4p
   '  ReleaseQueryMake
   ' REPORT
   '  r_Documentation
   
   On Error GoTo Proc_Err 
   
   Dim sSQL As String 

   Dim db As DAO.Database _ 
      ,rs As DAO.Recordset 
         
   Dim iCountFile As Integer _ 
      ,iCountQuery As Integer _ 
      ,nAdd As Long _ 
      ,nEdit As Long _ 
      ,nTotalAdd As Long _ 
      ,nTotalEdit As Long _ 
      ,dtmStart As Date _ 
      ,sMessage As String _ 
      ,sPattern As String _ 
      ,sQuery As String _ 
      ,sPath As String _ 
      ,bRecursive As Boolean 
   
   dtmStart = Now() 
   
   'Call StartCountLoopLink -- reset file counter
   Call StartCountLoopLink 
   
   With Me 
      sPath = .txtFolder 
      bRecursive = .chk_Recursive 
      sPattern = .txtPattern 
      .txtStart = dtmStart 
   End With 
   
   'Call LoopLinkPattern_s4p -- and return iCountFile
   Call LoopLinkPattern_s4p(sPath,sPattern,bRecursive,iCountFile) 
   
   'get number of queries created
   iCountQuery = 0 
   
   sSQL =  "SELECT count(*) as CalculatedRecordCount " _ 
      &  " FROM tFile AS F" _ 
      &  " WHERE(F.dtmAdd >=#" & dtmStart &  "# )" _ 
      &  ";"

   Set db = CurrentDb 
   Set rs = db.OpenRecordset(sSQL,dbOpenSnapshot) 
   With rs 
      iCountQuery = !CalculatedRecordCount 
   End With 
   
   sMessage = iCountFile &  " files linked " _ 
      &  " in " & iCountQuery &  " queries"
   If iCountFile <> iCountQuery Then 
      sMessage = sMessage & vbCrLf & vbCrLf _ 
         &  " some of the corrected file names are duplicated. " _ 
         &  "To make sure the ones you want are linked, " _ 
         &  "run again on just the latest folder(s)"
   End If 
   
   Debug.Print sMessage 
   
   'clear status bar
   SysCmd acSysCmdClearStatus 
   'release objects
   Call ReleaseLoopLink 
   Call ReleaseQueryMake 
   
   'open r_Documentation report
   DoCmd.OpenReport  "r_Documentation",acViewPreview _ 
      ,, "dtmEdit >=#" & dtmStart &  "#" _ 
      ,,dtmStart 
   
Proc_Exit: 
   On Error Resume Next 
   'release object variables
   If Not rs Is Nothing Then 
      rs.Close 
      Set rs = Nothing 
   End If 
   Set db = Nothing 
   Exit Sub 
  
Proc_Err: 
   MsgBox Err.Description,,_ 
        "ERROR " & Err.Number _ 
        &  "   cmdLoopLink_Click "

   Resume Proc_Exit 
   Resume 
   
End Sub 
'*************** Code End *****************************************************

Goto Top  

mod_Office_GetFolder_GetFile_s4p

Browse to a folder using the Office.FileDialog in VBA

Procedures:

Option Compare Database 
Option Explicit 

' module name: mod_Office_GetFolder_s4p
'*************** Code Start ***************************************************
' Purpose  : get a folder path using the Office file dialog box
'              browse to a folder, Office.FileDialog
' Author   : crystal (strive4peace)
' Code List: www.msaccessgurus.com/code.htm
' This code: https://msaccessgurus.com/VBA/Office_GetFolder.htm
'              added GetFile procedure
' LICENSE  :
'   You may freely use and share this code, but not sell it.
'   Keep attribution. Mark your changes. Use at your own risk.
'--------------------------------------------------------------------------------
'                              Constants
'--------------------------------------------------------------------------------
'bind early or late?
Public Const gIsEarly As Boolean = False 
'set compiler directive constant
#Const IsEarly = gIsEarly 
'--------------------------------------------------------------------------------
'                              GetFolder
'--------------------------------------------------------------------------------
Function GetFolder( _ 
   Optional psTitle As String =  "Select Folder" _ 
   ) As String 
'return folder path or "" if nothing chosen
'     for example, C:\MyPath
'crystal, strive4peace 220121, 230204
' REFERENCE for early binding
'     Microsoft Office #.0 Object Library
'     developed with 16.0

   'initialize return value
   GetFolder =  ""
   
   'dimension FileDialog object
   #If IsEarly Then 
      Dim fDialog As Office.FileDialog 
   #Else 
       Dim fDialog  As Object 
   #End If 

   '   msoFileDialogOpen = 1
   '   msoFileDialogSaveAs = 2
   '   msoFileDialogFilePicker = 3
   '   msoFileDialogFolderPicker = 4
   
   'Set File Dialog. 4=msoFileDialogFolderPicker
   Set fDialog = Application.FileDialog(4) 
   'set Title and GetFolder
   With fDialog 
      .Title = psTitle 
      If .Show Then 
         GetFolder = .SelectedItems(1) 
      End If 
   End With 
   'release object
   Set fDialog = Nothing 
End Function 

'--------------------------------------------------------------------------------
'                              GetFile
'--------------------------------------------------------------------------------
Function GetFile( _ 
   Optional psTitle As String =  "Select File" _ 
   ) As String 
'return file path and name
'     for example, C:\MyPath\filename.ext
'crystal, strive4peace 230227
' REFERENCE for early binding
'     Microsoft Office #.0 Object Library

   'initialize return value
   GetFile =  ""
   
   'dimension FileDialog object
   #If IsEarly Then 
      Dim fDialog As Office.FileDialog 
   #Else 
       Dim fDialog  As Object 
   #End If 
   
   'Set File Dialog. 3=msoFileDialogFilePicker
   Set fDialog = Application.FileDialog(3) 
   'set Title and GetFile
   With fDialog 
      .Title = psTitle 
      If .Show Then 
         GetFile = .SelectedItems(1) 
      End If 
   End With 
   'release object
   Set fDialog = Nothing 
End Function 
'*************** Code End *****************************************************

Goto Top  

mod_File_LoopLinkCsvDocument_Scripting_s4p

use recursive VBA to loop files and link using an Access query

Procedures:

The Main procedure is LoopLinkPattern_s4p. It's recursive, meaning it can call itself. Calls code in module:

Option Compare Database 
Option Explicit 

' REFERENCE for early binding
'  Microsoft Scripting Runtime
'     scrrun.dll
' Scripting.FileSystemObject
'  https://learn.microsoft.com/en-us/office/vba/language/reference/user-interface-help/filesystemobject-object


' module:  mod_File_LoopLinkCsvDocument_Scripting_s4p
'*************** Code Start ***************************************************
' Purpose  : procedures using the Microsoft Scripting Runtime library
'            loop through files in a folder and optionally subfolders
'            create queries
'            document paths, files, fields
' Author   : crystal (strive4peace)
' Code List: www.msaccessgurus.com/code.htm
' This tool: https://msaccessgurus.com/tool/LoopLinkDocument.htm
' LICENSE  :
'   You may freely use and share this code, but not sell it.
'   Keep attribution. Mark your changes. Use at your own risk.
'--------------------------------------------------------------------------------
'                              module declarations
'--------------------------------------------------------------------------------
#Const IsEarly = gIsEarly 

#If IsEarly Then  'early binding
   Private moFso As Scripting.FileSystemObject 
   Private moFile As Scripting.File 
   Private moFolder As Scripting.Folder 
#Else  'late binding
   Private moFso As Object 
   Private moFile As Object 
   Private moFolder As Object 
#End If 

Private moDb As DAO.Database 

Private mRsPath As DAO.Recordset _ 
   ,mRsFile As DAO.Recordset _ 
   ,mRsField As DAO.Recordset _ 
   ,nRs As DAO.Recordset _ 
   ,moQDF As DAO.QueryDef _ 
   ,moField As DAO.Field 

Private miCountFile As Integer 

'--------------------------------------------------------------------------------
'                              SetFso
'--------------------------------------------------------------------------------
Public Sub SetFso() 
   Set moFso = CreateObject( "Scripting.FileSystemObject") 
End Sub 
'--------------------------------------------------------------------------------
'                              ReleaseLoopLink
'--------------------------------------------------------------------------------
'run when done to cleanup
Public Sub ReleaseLoopLink() 
   Set moFso = Nothing 
   Set moDb = Nothing 
   Set moField = Nothing 
   Set moQDF = Nothing 
   If Not mRsField Is Nothing Then 
      mRsField.Close 
      Set mRsField = Nothing 
   End If 
   If Not mRsFile Is Nothing Then 
      mRsFile.Close 
      Set mRsFile = Nothing 
   End If 
   If Not mRsPath Is Nothing Then 
      mRsPath.Close 
      Set mRsPath = Nothing 
   End If 
End Sub 
'--------------------------------------------------------------------------------
'                              StartCountLoopLink
'--------------------------------------------------------------------------------
'run when start to initialize
Public Sub StartCountLoopLink() 
   miCountFile = 0 
End Sub 

'--------------------------------------------------------------------------------
'                              LoopLinkPattern_s4p
'--------------------------------------------------------------------------------
Public Sub LoopLinkPattern_s4p(psPath As String _ 
   ,Optional psFilePattern As String =  "*.csv" _ 
   ,Optional ByVal pbRecursive As Boolean = True _ 
   ,Optional ByRef piCountFile As Integer _ 
   ,Optional ByVal pnPathID As Long = -1 _ 
   ) 
'strive4peace ...230206, 230227, 230301, 2

   'PARAMETERs
   '  psPath is folder to loop and link CSV files
   'OPTIONAL
   '  psFilePattern is the file mask to match, default is "*.csv"
   '  pbRecursive = True to recurse
   '  RETURN piCountFile for number of files
   '  pnPathID < 0 to add Path record and get new PathID

   'CALLs
   '  SetFso
   '  GetPathIDNew
   '  itself if pbRecursive
   '     mod_GetQuery_LinkFile_s4p
   '  GetQuery_LinkFile_s4p
   
   On Error GoTo Proc_Err 

   Dim sFilename As String _ 
      ,sQueryname As String _ 
      ,sFolderPath As String _ 
      ,sExtension As String _ 
      ,sSQL As String _ 
      ,nPathID As Long _ 
      ,nFileID As Long _ 
      ,iNumFields As Integer _ 
      ,nNumRecord As Long _ 
      ,vListFields As Variant 
   
   Const LengthLISTFields As Integer = 220  'field size
   
   If moFso Is Nothing Or moDb Is Nothing Then 
      Call SetFso 
      Set moDb = CurrentDb 
      Set mRsPath = moDb.OpenRecordset( _ 
         "tPath",dbOpenDynaset,dbAppendOnly) 
      Set mRsFile = moDb.OpenRecordset( _ 
         "tFile",dbOpenDynaset,dbAppendOnly) 
      Set mRsField = moDb.OpenRecordset( _ 
         "tField",dbOpenDynaset,dbAppendOnly) 
   End If 
   
   'passed PathID
   If pnPathID < 0 Then 
      'path for top folder
      nPathID = GetPathIDNew(psPath) 
   Else 
      nPathID = pnPathID 
   End If 
   
   ' ---------------------------- Scripting.FileSystemObject
   With moFso 
      
      'RECURSIVE
      If pbRecursive <> False Then 
         For Each moFolder In .GetFolder(psPath).SubFolders 
            sFolderPath = moFolder.Path 
            'call GetPathIDNew
            pnPathID = GetPathIDNew(sFolderPath) 
            'call LoopLinkPattern_s4p, Recursively
            Call LoopLinkPattern_s4p(sFolderPath,psFilePattern _ 
               ,True,,pnPathID) 
         Next moFolder 
      End If 

      'loop files in folder of FileSystemObject for CSV files
      '  or whatever pattern is specified
      For Each moFile In .GetFolder(psPath).Files 
         
         sFilename = moFile.Name 
         
         ' make sure filename matches pattern, ie: CSV file
         If sFilename Like psFilePattern Then 

            'call GetQuery_LinkFile_s4p
            'RETURNS sExtension
            sQueryname = GetQuery_LinkFile_s4p(psPath _ 
               ,sFilename _ 
               ,sExtension) 
               
            If sQueryname =  "" Then 
               GoTo Proc_NextFile 
            End If 
                                        
            'store Path and File info
            With mRsFile 
               .AddNew 
               !PathID = nPathID 
               !File_name = sFilename 
               !FExt = sExtension 
               !FSize = moFile.Size 
               !FDateMod = moFile.DateLastModified 
               !Qry_name = sQueryname 
               .Update 
               .Bookmark = .LastModified 
               nFileID = !FileID 
               
               miCountFile = miCountFile + 1 

               iNumFields = 0 
               nNumRecord = 0 
               
               'store field data for the query
               vListFields = Null 
               
               moDb.QueryDefs.Refresh 
               Set moQDF = moDb.QueryDefs(sQueryname) 
               
               With mRsField 
                  For Each moField In moQDF.Fields 
                     iNumFields = iNumFields + 1 
                     vListFields = (vListFields +  ",") & moField.Name 
                     .AddNew 
                     !FileID = nFileID 
                     !Field_name = moField.Name 
                     !Field_type = moField.Type 
                     .Update 
                  Next moField 
               End With  'mrsField
               
               sSQL =  "SELECT count(*) as CountRecords " _ 
                  &  " FROM " & sQueryname 
                  
               Set nRs = moDb.OpenRecordset(sSQL,dbOpenSnapshot) 
               nNumRecord = nRs!CountRecords 
               nRs.Close 
               
               .Edit 
               !NumField = iNumFields 
               !NumRecord = nNumRecord 
               'truncate list of fields if it's too long
               !ListFields = Left(vListFields,LengthLISTFields) 
               !dtmEdit = Now() 
               .Update 
                                 
            End With  'mrsFile
                                          
         End If  'sFilename Like psFilePattern
Proc_NextFile: 
      Next moFile 

   End With   'moFso

   piCountFile = miCountFile 
   
Proc_Exit: 
   On Error Resume Next 

   Exit Sub 
  
Proc_Err: 
   MsgBox Err.Description _ 
       ,, "ERROR " & Err.Number _ 
        &  "   LoopLinkPattern_s4p"

   Resume Proc_Exit 
   Resume 
End Sub 
'--------------------------------------------------------------------------------
'                              GetPathIDNew
'--------------------------------------------------------------------------------
Function GetPathIDNew(psPath As String) As Long 
'230302 strive4peace
'add record to tPath and return the PathID
   With mRsPath 
      .AddNew 
      !Path_name = psPath 
      .Update 
      .Bookmark = .LastModified 
      GetPathIDNew = !PathID 
   End With 
End Function 

'*************** Code End *****************************************************

Goto Top  

mod_Query_Make_s4p

make or change an Access query given the name and SQL statement

Procedures:

Option Compare Database 
Option Explicit 

' module name: mod_Query_Make_s4p
'*************** Code Start ***************************************************
' Purpose  : make a query or change the SQL of a query
' Author   : crystal (strive4peace)
' Code List: www.msaccessgurus.com/code.htm
' This code: https://msaccessgurus.com/VBA/Query_Make.htm
' LICENSE  :
'   You may freely use and share this code, but not sell it.
'   Keep attribution. Mark your changes. Use at your own risk.
'--------------------------------------------------------------------------------
'                              module declarations
'--------------------------------------------------------------------------------
Dim moDb As DAO.Database 

'--------------------------------------------------------------------------------
'                              Query_Make_s4p
'--------------------------------------------------------------------------------
Sub Query_Make_s4p( _ 
   ByVal qName As String _ 
   ,ByVal pSql As String _ 
   ) 
'crystal (strive4peace) 220127
' if query already exists, update the SQL
' if not, create the query

   On Error GoTo Proc_Err 
   
   If moDb Is Nothing Then 
      Set moDb = CurrentDb 
   End If 
   
   With moDb 
      'Query: Type = 5
      If Nz(DLookup( "[Name]", "MSysObjects" _ 
          , "[Name]='" & qName _ 
          &  "' And [Type]=5"), "") =  "" Then 
          .CreateQueryDef qName,pSql 
      Else 
         'if query is open, close it
         On Error Resume Next 
         DoCmd.Close acQuery,qName,acSaveNo 
         On Error GoTo Proc_Err 
         .QueryDefs(qName).SQL = pSql 
      End If 
      .QueryDefs.Refresh 
      'refresh database window
      Application.RefreshDatabaseWindow 
   End With 
   
Proc_Exit: 
   On Error GoTo 0 
   Exit Sub 
   
Proc_Err: 
   MsgBox Err.Description,,_ 
     "ERROR " & Err.Number &  "  Query_Make"
    
   Resume Proc_Exit 

   'if you want to single-step code to find error, CTRL-Break at MsgBox
   'then set this to be the next statement
   Resume 
End Sub 
'--------------------------------------------------------------------------------
'                              ReleaseQueryMake
'--------------------------------------------------------------------------------
Public Sub ReleaseQueryMake() 
   Set moDb = Nothing 
End Sub 
'*************** Code End *****************************************************

Goto Top  

mod_GetQuery_LinkFile_s4p

VBA to make an Access query that links to a text file

Needs modules:

Option Compare Database 
Option Explicit 

'module: mod_GetQuery_LinkFile_s4p
'*************** Code Start ***************************************************
' Purpose  : get a folder path using the Office file dialog box
'              browse to a folder, Office.FileDialog
' Author   : crystal (strive4peace)
' Code List: www.msaccessgurus.com/code.htm
' This code: https://msaccessgurus.com/VBA/GetQuery_LinkCsv.htm
'              this code has been slightly modified from what's posted
' LICENSE  :
'   You may freely use and share this code, but not sell it.
'   Keep attribution. Mark your changes. Use at your own risk.
'--------------------------------------------------------------------------------
'                              GetQuery_LinkFile_s4p
'--------------------------------------------------------------------------------
Public Function GetQuery_LinkFile_s4p( _ 
   psPath As String _ 
   ,psFilename As String _ 
   ,psExtension As String _ 
   ,Optional ByRef pbStripBOM As Boolean = False _ 
   ) As String 
   
'return the name of the query that was created or modified
'return pbStripBOM
'return psExtension

'230121, 27 s4p, 230205-6, 230228, 230301
   'CALLs
   '     mod_CorrectName_s4p
   '  CorrectName_s4p
   '     mod_GetSQL_LinkCsv_s4p
   '  GetSQL_LinkCsv_s4p
   '     mod_File_RemoveUTF8bom_s4p
   '  TextFileStripBOM_s4p
   '     mod_Query_Make_s4p
   '  Query_Make_s4p

      
   'initialize return value
   GetQuery_LinkFile_s4p =  ""
   
   Dim sSQL As String _ 
      ,sQueryname As String _ 
      ,sPathFile As String _ 
      ,sFieldname As String _ 
      ,iPos As Integer _ 
      ,bRemoveBOM As Boolean 
      
   GetQuery_LinkFile_s4p =  ""
   
   '--------------------- customize if desired
   'test for UTF-8 Unicode BOM
   bRemoveBOM = True 
   'create the query name
   iPos = InStrRev(psFilename, ".") 
   psExtension = Right(psFilename _ 
      ,Len(psFilename) - iPos) 
   
   sQueryname =  "qLink_" _ 
      & psExtension &  "_" _ 
      & CorrectName_s4p( _ 
         Left(psFilename,iPos - 1)) 
   '---------------------
   
   Select Case psExtension 
   Case  "CSV", "TXT"
      'call GetSQL_LinkCsv_s4p
      sSQL = GetSQL_LinkCsv_s4p(psPath,psFilename) 
      'remove BOM unicode indicator if there
      If bRemoveBOM Then 
         'combine Path and File
         sPathFile = psPath _ 
            & IIf(Right(psPath,1) <>  "\", "\", "") _ 
            & psFilename 
         'strip BOM (byte order mark) from beginning of file for UTF-8
         'call TextFileStripBOM_s4p
         If TextFileStripBOM_s4p(sPathFile) <> False Then 
            'file was modified
            pbStripBOM = True 
         End If 
      End If 
   Case Else 
'      MsgBox "Don't know what to do with " & psExtension & " file" _
         ,, "Need VBA CodE IN GetQuery_LinkFile_s4p"
      'skip this file
      Exit Function 
   End Select 
   
   
   'create or overwite query
   'call Query_Make_s4p
   Call Query_Make_s4p(sQueryname,sSQL) 

   Debug.Print sQueryname,Format(pbStripBOM, "0") 
   
   GetQuery_LinkFile_s4p = sQueryname 
   
End Function 

'*************** Code End *****************************************************

Goto Top  

mod_CorrectName_s4p

Remove spaces and unwanted characters from a string for a name using a VBA function

Option Compare Database 
Option Explicit 

' module name: mod_CorrectName_s4p
'*************** Code Start ***************************************************
' Purpose  : replace unwanted characters in string with underscore (_)
' Author   : crystal (strive4peace)
' Code List: www.msaccessgurus.com/code.htm
' This code: https://msaccessgurus.com/VBA/Fx_CorrectName.htm
' LICENSE  :
'   You may freely use and share this code, but not sell it.
'   Keep attribution. Mark your changes. Use at your own risk.
'--------------------------------------------------------------------------------
'                              CorrectName_s4p
'--------------------------------------------------------------------------------'
Function CorrectName_s4p( _ 
   ByVal psName As String _ 
   ) As String 
'strive4peace 221223, 230129
' replace spaces and unwanted characters with underscore _
' if 2 in a row, only use 1
' trim beginning and end

   Dim i As Integer _ 
      ,sName As String _ 
      ,sChar As String * 1 _ 
      ,sLastChar As String * 1 _ 
      ,sNewChar As String * 1 _ 
      ,iPos As Integer 
 
   'PARAMETERS
   'psName is the string you want to correct
 
   'EXAMPLE USEAGE
   '  on the AfterUpdate event of a control
   '  =CorrectName([controlname])
   '
   'in a query:
   'field --> CorrectName: CorrectName_s4p([strFieldname])
 
   'EXAMPLE
   ' ? CorrectName_s4p("as(,48209j@##@!")
   ' --> as_48209j_
 
   CorrectName_s4p =  ""
   If psName =  "" Then Exit Function 
   
   Dim sBadCharacters As String 
   sBadCharacters =  "`!@#$%^&*()+-=|\:;""'<>,.?/ "
 
   psName = Trim(psName) 
 
   For i = 1 To Len(psName) 
      sChar = Mid(psName,i,1) 
 
      If InStr(sBadCharacters,sChar) > 0 Then 
         sNewChar =  "_"
      Else 
         sNewChar = sChar 
      End If 
 
      If sLastChar =  "_" And sNewChar =  "_" Then 
         'leave the same for multiple characters to replace in a row
      Else 
         sName = sName & sNewChar 
      End If 
 
      sLastChar = sNewChar 
   Next i 
 
   CorrectName_s4p = sName 
 
End Function 
'*************** Code End *****************************************************

Goto Top  

mod_File_RemoveUTF8bom_s4p

Remove byte order mark () for UTF-8 files using a VBA function

When data is stored in UTF-8 format, there is a byte order mark at the beginning that comes across as 3 odd characters,  so this code strips them away. Most of the time, the extra support isn't needed. If you do need the files to stay in UTF-8, you can link to them with tables. I couldn't find a way, however, to specify UTF-8 in the connect string for queries.

Option Compare Database 
Option Explicit 

' module name: mod_File_RemoveUTF8bom_s4p
'*************** Code Start ***************************************************
' Purpose  : strip  from beinning of file contents
' Author   : crystal (strive4peace)
' Code List: www.msaccessgurus.com/code.htm
' This code: https://msaccessgurus.com/VBA/File_RemoveUTF8bom.htm
' LICENSE  :
'   You may freely use and share this code, but not sell it.
'   Keep attribution. Mark your changes. Use at your own risk.
'--------------------------------------------------------------------------------
'                              TextFileStripBOM_s4p
'--------------------------------------------------------------------------------'
Public Function TextFileStripBOM_s4p( _ 
   psPathFile As String _ 
   ) As Boolean 
'230127 strive4peace
' strip UTF-8 BOM (byte order mark) 
' from beginning of file

   'Return
   '  False if no change made to file
   '  True if file was changed
   
   TextFileStripBOM_s4p = False 
   
   Dim iFile As Integer _ 
      ,sFileContents As String _ 
      ,s3 As String 
      
   'get a numeric file handle to refer to the file
   iFile = FreeFile 
   
   'open the file for reading
   Open psPathFile For Input As iFile 
   
   'get first 3 characters of file
   s3 = Input(3,iFile) 
   
   'see if there is a marker for UTF-8
   If s3 <>  "" Then 
      'no changes to file
      GoTo Proc_Exit 
   End If 
   'get rest of file
   sFileContents = Input(LOF(iFile) - 3,iFile) 
   Close iFile 

   'over-write file without BOM characters
   Open psPathFile For Output As iFile 
   Print #iFile,sFileContents 
   
   'indicate that a change to the file was made
   TextFileStripBOM_s4p = True 
   
Proc_Exit: 
   On Error Resume Next 
   Close iFile 
   Exit Function 
  
Proc_Err: 
   MsgBox Err.Description _ 
       ,, "ERROR " & Err.Number _ 
        &  "   TextFileStripBOM_s4p"

   Resume Proc_Exit 
   Resume 
End Function 
'--------------------------------------------------------------------------------
'                              testTextFileStripBOM_s4p
'--------------------------------------------------------------------------------'
Sub testTextFileStripBOM_s4p() 
'230127 s4p test TextFileStripBOM_s4p

   'CALLs
   '  TextFileStripBOM_s4p
   
   Dim sPath As String _ 
      ,sFile As String _ 
      ,sPathFile As String 
   
   sPath =  "C:\MyPath"        '------------ customize
   sFile =  "Filename.csv"     '------------ customize
      
   sPathFile = sPath _ 
      & IIf(Right(sPath,1) <>  "\", "\", "") _ 
      & sFile 
   
  ' Call TextFileStripBOM_s4p(sPathFileIn, sPathFileOut)
   MsgBox TextFileStripBOM_s4p(sPathFile),, "Done"
End Sub 
'*************** Code End *****************************************************

Goto Top  

mod_GetSQL_LinkCsv_s4p

Return SQL statement to link to a text file using a VBA function

Option Compare Database 
Option Explicit 

' module name: mod_GetSQL_LinkCsv_s4p
'*************** Code Start ***************************************************
' Purpose  : Function to create and return SQL to link to a CSV file
' Author   : crystal (strive4peace)
' Code List: www.msaccessgurus.com/code.htm
' This code: https://msaccessgurus.com/VBA/GetSQL_LinkCsv.htm
' LICENSE  :
'   You may freely use and share this code, but not sell it.
'   Keep attribution. Mark your changes. Use at your own risk.
' Then use the SQL to create a saved query or to open a recordset
'--------------------------------------------------------------------------------
'                              GetSQL_LinkCsv_s4p
'--------------------------------------------------------------------------------'
Public Function GetSQL_LinkCsv_s4p( _ 
   psPath As String _ 
   ,psFilename As String _ 
   ) As String 
'230131 strive4peace
   Dim sConnect As String 
   
   sConnect =  "[Text;DATABASE=" _ 
      & psPath _ 
      &  "].[" & psFilename _ 
      &  "]"
   
   GetSQL_LinkCsv_s4p =  "SELECT Q.* FROM " & sConnect &  " as Q;"
   
End Function 
'--------------------------------------------------------------------------------
'                             testSQL_LinkCsv_s4p
'--------------------------------------------------------------------------------'
Sub testGetSQL_LinkCsv_s4p() 
   Dim sPath As String _ 
      ,sFile As String _ 
      ,sSQL As String 
   
   sPath =  "C:\MyPath"        '------------ customize
   sFile =  "MyFilename.csv"   '------------ customize
   
   'Call GetSQL_LinkCsv_s4p
   sSQL = GetSQL_LinkCsv_s4p(sPath,sFile) 
   
   MsgBox sSQL,, "done"
End Sub 

'*************** Code End *****************************************************

Goto Top  

code behind report r_Documentation

This report shows data in the tPath, tFile, and tField tables. This information is created during the loop and link process.

Running sums are used to count the files in each path and for the whole report.

When a report is filtered by the menu form, the As Of date/time is reported in the page header.

Display data structure for queries linked to CSV files using an Access report.

'cbr: r_Documentation
'*************** Code Start ***************************************************
' Purpose  : show data structure information for queries
' Author   : crystal (strive4peace)
' Code List: www.msaccessgurus.com/code.htm
' This tool: https://msaccessgurus.com/VBA/LoopLinkDocument.htm
' LICENSE  :
'   You may freely use and share this code, but not sell it.
'   Keep attribution. Mark your changes. Use at your own risk.
'--------------------------------------------------------------------------------
'                              Report_Load
'--------------------------------------------------------------------------------
Private Sub Report_Load() 
'230228 strive4peace, 230302
   Dim sAsOf As String 
   With Me 
      If Not IsNull(.OpenArgs) Then 
         sAsOf =  "as of " & .OpenArgs 
      End If 
      .Label_AsOf.Caption = sAsOf 
   End With 
End Sub 
'--------------------------------------------------------------------------------
'                              GroupFooter0_Format for Path
'--------------------------------------------------------------------------------
Private Sub GroupFooter0_Format( _ 
   Cancel As Integer,FormatCount As Integer) 
'path footer
   Me.txtCountFilePath = Me.txtRunSumPath 
End Sub 
'--------------------------------------------------------------------------------
'                              GroupFooter3_Format for Report
'--------------------------------------------------------------------------------
Private Sub GroupFooter3_Format( _ 
   Cancel As Integer,FormatCount As Integer) 
'report footer
   Me.txtCountFileReport = Me.txtRunSumReport 
End Sub 
'*************** Code End *****************************************************
' Code was generated with colors using the free Color Code add-in for Access.

Goto Top  

Reference

Some of the code used by this application is posted on msAccessGurus with more detailed explanations.

Get Folder

VBA to open a an Office File Dialog box to browse to a folder and return the path.

mod_Office_GetFolder_s4p

Get SQL for a Linked CSV File

VBA function to return an SQL statement that links to a text file. Use the result to make a query or open a recordset.

mod_GetSQL_LinkCsv_s4p

Remove 

VBA to remove the BOM (byte order mark), , from the beginning of files stored in UTF-8 format.

mod_File_RemoveUTF8bom_s4p

Correct Name

Remove spaces and unwanted characters from a string for a name using a VBA function.

mod_CorrectName_s4p

Make a Query

VBA to make or change a query in Access given the query name and SQL statement.

mod_Query_Make_s4p

Goto Top  

Backstory

This is a basic version of an application that I developed for a company that gets lots of CSV files with metrics such as temperature and pressure for equipment in a large facility.

The data structure had to be analyzed because each CSV file could have different fields. Access was used to manipulate and combine data that was then written to another system for reporting.

If you find this useful, please let me know. Donations are always appreciated, thank you

Share with others

Here's the link for this page in case you want to copy it and share it with someone:

https://msaccessgurus.com/tool/LoopLinkDocument.htm

or in old browsers:
http://www.msaccessgurus.com/VBA/LoopLinkDocument.htm

Get Development and Tutoring with Access

Let's connect and team-develop your application together. I teach you how to do it yourself. My goal is to empower you.

While we build something great together, I'll pull in code and features from my vast libraries as needed, cutting out lots of development time. I'll give you lots of links to good resources.

Access is great at reading data in all kinds of formats and structures. Contact me if you could benefit from good ideas, great code, and helpful training. Email me at training@msAccessGurus.com

~ crystal

the simplest way is best, but usually the hardest to see

Goto Top