Move Files to New Directory based on SQL Query Data - vba

Hoping someone could help:)
I have an MS Access table that holds file names along with other data Example:
AcctNum, FileName
12345, abc123.pdf
I have written a SQL to sort the file name based on account number. Example: Select * from tblTest where AcctNum='12345'
Files with these file names are located in a directory (C:\Test\<filename>.pdf)
I need to move the selected files based on the SQL I've written to move those files to a different directory (D:\Test\FromCode). Filename 'abc123.pdf' is located in C:\Test move to D:\test, loop through SQL results to move files based on criteria.
Attached is some VBA that I have written that I can get a file to copy from source to destination manually when I input the exact filename (as seen in the code, the file name is "abc123"), but I want to tie it to the mysql query recordset and move the group which will contain 1000's of files. Anyone know the best way I can tie this to recordset?
Appreciate any direction/help you provide.
Sub UpdateDirectory()
Dim objFSO As Object
Dim objFolder As Object
Dim objFile As Object
Dim rs As DAO.Recordset
Dim db As DAO.Database
Dim mysource As String
Dim mydes As String
Dim mysql As String
mysql = "SELECT * from tblTest where ACCTNUM = 123456"
mysource = "C:\Test"
mydes = "D:\Test\FromCode\"
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFolder = objFSO.GetFolder(mysource)
Set db = CurrentDb
Set rs = db.OpenRecordSet(mysql)
'I want to tie mysql recordset to below to move all files/records based
'on ACCTNUM. This could result in moving 1000's of files to
'destination.
For Each objFile In objFolder.Files
If InStr(1, objFile.Name, "abc123") > 0 Then
Debug.Print "yes"
objFSO.CopyFile objFile, mydes
Else
Debug.Print "no"
End If
Next
'clean
Set objFolder = Nothing
Set objFile = Nothing
Set objFSO = Nothing
End Sub

Here is your code with a working answer: To be sure, #June7 is correct, but putting the answer in your context:
Sub UpdateDirectory()
Dim objFSO As Object
Dim objFolder As Object
Dim objFile As Object
Dim rs As DAO.Recordset
Dim db As DAO.Database
Dim mysource As String
Dim mydes As String
Dim mysql As String
mysql = "SELECT * from tblTest where ACCTNUM = 123456"
mysource = "C:\Test" 'Missing backslash - added later
mydes = "D:\Test\FromCode\"
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFolder = objFSO.GetFolder(mysource)
Set db = CurrentDb
Set rs = db.OpenRecordSet(mysql)
'I want to tie mysql recordset to below to move all files/records based
'on ACCTNUM. This could result in moving 1000's of files to
'destination.
While Not rs.EOF
sourceFile = mysource & "\" & rs!Filename 'Added a missing backslash
destFile = mydes & rs!Filename
If Dir(sourceFile) <> "" Then 'If sourceFile exists, then Dir(sourceFile) will return it's name, otherwise empty string
FileCopy sourceFile, destFile
End If
rs.MoveNext
Wend
End Sub

That SQL is not sorting records, it is filtering.
The recordset serves no purpose if you do not loop through records. If you do not want to simply copy all files and the complete account number is not part of filename, then need to loop through recordset, not folder. Use filename from field in the file copy. FSO is not needed - Access FileCopy method can serve.
...
mysource = "C:\Test\"
...
Do While Not rs.EOF
If Dir(mysource & rs!Filename) <> "" Then FileCopy mysource & rs!Filename, mydes & rs!Filename
Loop

Related

MS ACCESS VBA Move/Copy Files

I am using the below code to reference a table that has full path information to move (or copy) files from 1 location to another. However, it's not moving anything, but is completing per my Debug.Print message (Move Complete 2/22/2021 1:22:41 PM). Any thoughts on what I'm missing?
Additionally, I'd like to build the folder/subfolder structure where the file was located in the source...but don't know how to achieve that...and pointers on how to do this?
Sub copy_files_from_table()
Dim FSO As Object
Dim source As String
Dim destination As String
Dim SQL As String
Dim RS As DAO.Recordset
Dim db As DAO.Database
SQL = "select * from file_test"
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set db = CurrentDb
Set RS = db.OpenRecordset(SQL)
source = RS!LocalFile
destination = "C:\Temp\Test"
While Not RS.EOF
If Dir(source, vbDirectory) <> "" Then
objFSO.CopyFolder source, destination:=destination '
Debug.Print "Move Folder Command Complete From: " & destination
Else
End If
RS.MoveNext
Wend
Debug.Print "Move Complete " & Now()
End Sub
Appreciate any help provided.
So far, I have gotten the following code to work on file paths <259; however, anything longer is causing the code to error. Since I'm pretty green on coding:) any suggestions how I can get around the long file path names?
Sub CopyFilesFromTable2()
On Error GoTo ErrorHandler
Dim source As String
Dim destination As String
Dim FSO As New FileSystemObject
Dim SQL As String
Dim RS As DAO.Recordset
Dim db As DAO.Database
'Test Table
SQL = "select * from file_test"
'Prod Table
'SQL = "select * from file"
Set FSO = CreateObject("Scripting.FileSystemObject")
Set db = CurrentDb
Set RS = db.OpenRecordset(SQL)
source = RS!LocalFile
File = VBA.FileSystem.Dir(source)
destination = "D:\Temp\Test\"
With RS
If Not .BOF And Not .EOF Then
.MoveLast
.MoveFirst
While (Not .EOF)
FSO.CopyFile RS!LocalFile, destination
.MoveNext
Wend
End If
.Close
End With
ExitSub:
Set RS = Nothing
'set to nothing
MsgBox "Done!"
Exit Sub
ErrorHandler:
MsgBox Err, vbCritical
Resume ExitSub
End Sub

MSAccess VBA - Loop only through user-selected records

I'm trying to iterate through the records of a database, in order to save all of the attachments associated to certain fields of each record. I managed to find a way to properly export the attachments by cycling though the entire table. However, it would be way more useful to export only the attachments of the records previously selected by the user in the table form.
This is what my code structure looks like at the moment:
Public Function Main()
Dim dbs As DAO.Database
Dim rst As DAO.Recordset2
Dim rsA As DAO.Recordset2
Dim CRT As DAO.Field2
Dim cat As DAO.Field2
Dim prg As DAO.Field2
Dim strFullPath As String
Dim CatPrg As String
Dim fso As New FileSystemObject
'Get the database, recordset, and attachment field
Set dbs = CurrentDb
Set rst = dbs.OpenRecordset("Archieve_Table")
Set STF = rst("STF")
Set cat = rst("CAT")
Set prg = rst("PRG")
'Navigate through the table
Do While Not rst.EOF
CatPrg = cat.Value & "-" & prg.Value
'Get the recordset for the Attachments field STF
Set rsA = STF.Value
'Save all attachments in the field
Do While Not rsA.EOF
strPath = CurrentProject.Path & "\Export\" & CatPrg & "\STF\"
strFullPath = strPath & rsA("FileName")
'Make sure the file does not exist and save
If Dir(strFullPath) = "" Then
rsA("FileData").SaveToFile strFullPath
End If
'Next attachment
rsA.MoveNext
Loop
rsA.Close
'Next record
rst.MoveNext
Loop
rst.Close
dbs.Close
Set STF = Nothing
Set rsA = Nothing
Set rst = Nothing
Set dbs = Nothing
Set cat = Nothing
Set prg = Nothing
End Function
Probably I need to add some conditions at Set rst = dbs.OpenRecordset("Archieve_Table") when I set the OpenRecordset.

How do I save all the attachments in a single field for all records in a MS Access table?

I am working with a Microsoft Access 2010 database.
I have a number of pictures saved as attachments in one field of a table.
How do I save all the pictures to a local folder for all records simultaneously?
I need to preserve the names of the attachments but they can all go in the same folder.
Thank you :-)
Use below sub to save all attachment file for all records.
Private Sub cmdLoadPicture_Click()
Dim dbs As DAO.Database
Dim rst As DAO.Recordset2
Dim rsA As DAO.Recordset2
Dim fld As DAO.Field2
Dim savePath As String
savePath = "C:\Users\Harun.Rashid\Pictures\Screenshots\" 'Folder path to save files
Set dbs = CurrentDb
Set rst = dbs.OpenRecordset("tblEmpInfo") 'tblEmpInfo is table name
Set fld = rst("EmpPhoto") 'EmpPhoto is Field name to table with attachment data type.
Do While Not rst.EOF 'Loop through all records of table.
Set rsA = fld.Value
On Error Resume Next 'Omit errors if file already exist
Do While Not rsA.EOF 'Loop through all attachment of single record
rsA.Fields("FileData").SaveToFile savePath 'Save file to disk
rsA.MoveNext
Loop
rst.MoveNext
Loop
rst.Close
dbs.Close
Set fld = Nothing
Set rst = Nothing
Set dbs = Nothing
End Sub

How to Get UTC of file DateLastModified in VBA?

I need to find from an Access DB if any file in a folder got changed. For this reason I created a table containing the file information (name and DateLastModified). However there is the problem, that Windows always adjusts the DateLastModified to the local time zone and this value will even change on daylight savings (means: DateLastModified will change when DST activates/deactivates)!
To overcome this and to find the files true 'DateLastModified'-date I use FileSystemObject to get 'DateLastModified' and convert the returned value to UTC by means of Function GetUTC. Then I store this value in the database. I carefully tested GetUTC - it will return a value not depending on DST (tested for time zones CET and CEST).
Re-querying the folder and comparing a newly calculated 'DateLastModified' against the stored 'DateLastModified' will fail for approximately 15%-35% of the files - is seems random which files fail! Could it be that DT.GetVarDate(False) in GetUTC does not always return the same binary value?
However using debug.print always shows the same Date & Time for the failing files and the value stored in the database! MS specs says the resolution of datatype 'Date' is one second. So I do not understand how 2 Dates that show the same value will result to false when compared! Sample output of a failed file:
1477 493 18.12.2013 19:03:26 18.12.2013 19:03:26 scanColor0010.pdf
How can I make this work?
Option Compare Database
Option Explicit
Public ws As Workspace
Public db As Database
Function GetUTC(dLocalTimeDate As Date) As Date
Dim DT As Object
Dim curTime As Date
curTime = Now()
Set DT = CreateObject("WbemScripting.SWbemDateTime")
DT.SetVarDate curTime
GetUTC = dLocalTimeDate - curTime + DT.GetVarDate(False)
End Function
'------------------------------------------------------------
' Test_UTC_Click
'
'------------------------------------------------------------
Private Sub Test_UTC_Click()
Dim colFiles As New Collection
Dim vFile As Variant
Dim rst As Recordset
Dim fso As FileSystemObject
Dim f As File
Dim lngCountWrong As Long
Dim lngCount As Long
Set ws = DBEngine.Workspaces(0)
Set db = CurrentDb()
RecursiveDir colFiles, "Y:\", "*.pdf", False
Set fso = CreateObject("Scripting.FileSystemObject")
For Each vFile In colFiles
Set f = fso.GetFile(vFile)
Set rst = db.OpenRecordset("SELECT tblFiles.*, tblFiles.fileName FROM tblFiles WHERE (((tblFiles.fileName)=""" & f.Name & """));")
rst.MoveFirst
lngCount = lngCount + 1
If (rst!fileDateModified = GetUTC(f.DateLastModified)) Then
'Ok, this is always expected
Else
'Uuuups - what went wrong?
lngCountWrong = lngCountWrong + 1
Debug.Print lngCount, lngCountWrong, rst!fileDateModified, GetUTC(f.DateLastModified), f.Name
End If
rst.Close
Set f = Nothing
DoEvents
Next vFile
Debug.Print "finished", lngCount
Set fso = Nothing
End Sub
'------------------------------------------------------------
' CreateTestdata_Click
'
'------------------------------------------------------------
Private Sub CreateTestdata_Click()
Dim colFiles As New Collection
Dim vFile As Variant
Dim rst As Recordset
Dim fso As FileSystemObject
Dim f As File
Set ws = DBEngine.Workspaces(0)
Set db = CurrentDb()
db.Execute "DELETE tblFiles.* FROM tblFiles;"
Set rst = db.OpenRecordset("SELECT tblFiles.* FROM tblFiles;")
RecursiveDir colFiles, "Y:\", "*.pdf", False
Set fso = CreateObject("Scripting.FileSystemObject")
For Each vFile In colFiles
Set f = fso.GetFile(vFile)
rst.AddNew
rst!filename = f.Name
Debug.Print f.Name
rst!fileDateModified = GetUTC(f.DateLastModified)
rst.Update
Set f = Nothing
DoEvents
Next vFile
Set fso = Nothing
rst.Close
Debug.Print "Finished creating"
MsgBox "Finished creating"
End Sub
Rewrite
If (rst!fileDateModified = GetUTC(f.DateLastModified)) Then
'Ok, this is always expected
Else
to
If Datediff("s",rst!fileDateModified,GetUTC(f.DateLastModified)) = 0 Then
'Ok, this is always expected
Else
Further reading on Datediff
Further reading on How to store, calculate, and compare Date/Time data in Microsoft Access. Although this article is on Access it should be similar in Excel

Access VBA how to read a txt file from an attachment field

I wrote an R function, which is too long to be stored even in a memo field. There is probably a way of reading it if I store it in a txt file somewhere in my hard drive. But can I save this txt file in an attachment field and read it with vb code? So far the nearest answer I got is as below to print names of the attachment, but not what is in the attachment.
Dim dbs As DAO.Database
Dim rst As DAO.Recordset2
Dim rsA As DAO.Recordset2
Dim fld As DAO.Field2
'Get the database, recordset, and attachment field
Set dbs = CurrentDb
Set rst = dbs.OpenRecordset("tblAttachments")
Set fld = rst("Attachments")
'Navigate through the table
Do While Not rst.EOF
'Print the first and last name
Debug.Print rst("FirstName") & " " & rst("LastName")
'Get the recordset for the Attachments field
Set rsA = fld.Value
'Print all attachments in the field
Do While Not rsA.EOF
Debug.Print , rsA("FileType"), rsA("FileName")
'Next attachment
rsA.MoveNext
Loop
'Next record
rst.MoveNext
Loop
I never store files in attachment fields. Instead I will store the absolute path to the file in the table and then use VBA to display or modify the file.
You can use the following code to print the contents of a text file to the console. NOTE: You will need to add the Microsoft Scripting Runtime reference to your project.
Dim fso As FileSystemObject
Dim ts As TextStream
Set fso = CreateObject("Scripting.FileSystemObject")
' use path stored in table vvv here
Set ts = fso.OpenTextFile(path, ForReading, False, 0)
Do While ts.AtEndOfStream <> True
debug.print ts.ReadLine
Loop
ts.Close