Access SQL Query to Add or Update Values - sql

I have an Access database that I need to update every week based on a fixed length text file
The file contains some new records and some updates.
Currently, I am using an ADODB connection to treat the file as a recordset, looping thru its records and adding or updating my records if needed.
The problem is that this process is very slow, complicated and can generate some errors.
Is there a way to achieve the same results using Access SQL?

Since I don't believe Access has any sort of "upsert" functionality, my first inclination would be to create two queries -- an insert query and an update query -- and add a WHERE clause to each to limit the insert and the update to the appropriate records. Then you can combine then under a single transaction, something like this:
With conn 'Assuming you keep using the ADO recordset; you could use DAO instead
.BeginTrans
.Execute "UpdateQuery"
.Execute "InsertQuery"
.CommitTrans
End With
Maybe not ideal, but better than a loop.

I do quite a lot of importing from Excel and have found the easiest way is to import the file to a table and run all the updates/ inserts from this as it is materially quicker once you have the data in a local table.
You could create the table on the fly but I prefer to have the table structure all setup and use TransferText to import, where you can use an import spec.
Loosely to set this up:
Create your table with appropriate field names and data types
Manually import the data from your text file and save the import spec
Use VBA to import future text files and trigger the update/ insert queries
Code could look something like this:
' Folder where files to be imported are saved
strFilePath = "C:\myFolder\"
' Look for a .txt file in that folder
strFileName = Dir(strFilePath & "*.txt")
' Loop through all .txt files until each is imported
Do Until strFileName = ""
strFile = strFilePath & strFileName
' Import the file to a temporary table where "myImportSpec" is what you saved
' the import spec as when you did the manual import and "tbl_IMPORT_Temp"
' is the table you created to run your queries from
'NOTE: This is what i use for .csv files and haven't tested on .txt but
' I think it should work
DoCmd.TransferText acImportDelim, "myImportSpec", "tbl_IMPORT_Temp", strFile
DoCmd.OpenQuery "qryUpdateQuery", acViewNormal
DoCmd.OpenQuery "qryAppendQuery", acViewNormal
' Copy the .txt file to a new folder
FileCopy strFile, strFilePath & "Successful\" & strFileName
' Delete the original file so it isn't imported again
Kill strFile
NextFile:
' Clear your temp import table
DoCmd.RunSQL "DELETE * FROM tbl_IMPORT_Temp"
' Get the next file to be imported
strFileName = Dir(strFilePath & "*.txt")
Loop
Hope this helps. Simon

Related

Automate load of csv data in ms access, and include autonumer primary key ID field

I am having trouble adding a primary key autonumber ID field to a ms access table which I have loaded using the DoCmd.transfertext script. I have tried a sql script and even doing it manually but I get the following error: "File sharing lock count exceeded. Increase MaxLocksPerFile registry entry".
I have tried countering this using DAO.DBEngine.SetOption dbmaxlocksperfile,1500000, but then I get another bug saying I have reached the memory limit, note the data set has 900 000 rows.
The funny thing is if I manually load the file using the text import wizard, I can set the wizard to add the primary key ID field, and it works perfectly fine. I know the DoCmd.TransferText doesn't allow the addition of an autonumber primary key field, so I am wondering how best to load my data with the autonumber ID field?
See my code below:
Function Data_Load()
Dim strSQL
DoCmd.TransferText acImportDelim, "xxx Import Specification", "xxx", "C:\xxx.csv", True
DAO.DBEngine.SetOption dbMaxLocksPerFile, 1500000
strSQL = "ALTER TABLE PDQ ADD COLUMN ID AUTOINCREMENT"
Set rs = CurrentDb.CreateQueryDef("strSQL")
DoCmd.RunSQL (strSQL)
DAO.DBEngine.SetOption dbMaxLocksPerFile, 9500
End Function
Since the import wizard can do this (and it works), use it!
One-time preparations:
Copy a sample import file to a generic location from where all saved imports will be run
Do a manual import into table "myTable", and save it at the end as e.g. "myTable_Import".
Then you can run it with DoCmd.RunSavedImportExport :
Sub TestSavedImport()
On Error Resume Next
DoCmd.DeleteObject acTable, "myTable"
On Error GoTo 0
' copy your actual import file to the generic path\file
' that you used during the manual import
' ...
' run saved import
DoCmd.RunSavedImportExport "myTable_Import"
' rename to actual target name
DoCmd.Rename "RealTableName", acTable, "myTable"
End Sub

How to import text file into existing Access table using Visual Basic(button click) (Visual Basic 2015)) [duplicate]

I am trying to automate the adding of new text files, which all have the same (known) layout.
The columns are separated using tabs (the TAB button). My question is, is it possible to do this in VBA? Like, in the access wizard for importing text files?
I am using the DoCmd.TransferText method in VBA
You'll need to go through the wizard once to make your specification file. TO do this import your text file like normal but before you get too deep into the wizard click on the bottom left, the "Advanced..." button. This is where you make your spec file.
Make ll these columns match your input file, data types and all. Be sure to select the {tab} field delimiter and the appropriate text qualifier if you are using one.
Save your spec (which can later be edited by coming back to this same screen and clicking Specs... then saving over your old one)
Now you can use in VBA like this
DoCmd.TransferText acImportDelim, "your spec name", "destination table name", sourceFilePath
There is a parameter HasFieldNames that you'll have to decide if it is true or false based on your file.
With the import wizard the downside is that for even the slightest change in file format, you'll have to click through all those steps yet again to get the import working.
Check out #Remou's answer in ms Access import table from file in a query for a way to do it in straight SQL. I am actually using the same method in a project of mine. I use something like this (see my link for the details):
insert into MyTable (column-list...)
select (column-list...)
from [data-source-specifications].[file-name]
any-other-clauses...;
Just one caveat. If you put this SQL syntax into a normal Access query object, there's a good chance that Access will mangle it to the point where it won't even be able to open the query object. So compose and save the query in a text file while you try it out in Access. Once the query is tested and working, save it in a VBA subroutine so that Access will run it exactly as is, like so:
sub MyTableImport()
sqlStr = " insert into MyTable (column-list) " ' leave a space at the
sqlStr = sqlStr & "select (column-list...) " ' end of each line of the string
sqlStr = sqlStr & "from [data-source-specifications].[file-name] "
sqlStr = sqlStr & "any-other-clauses... ;"
DoCmd.RunSQL sqlStr
end sub

Closing connection to Excel spreadsheet in classic ASP using ODBC

Kind of a wordy title but I have a classic ASP application I am trying to write where a user uploads an Excel spreadsheet and then I take that spreadsheet and import the data into SQL.
I have everything working great but the one thing I'm running into is that after I open the spreadsheet using ODBC and close all the objects that reference it, if I try to delete the file, I get a permission denied error.
If I try to sweep the temp directory before uploading and I run into a previously uploaded file (say within the last two minutes), I get the permission denied error.
If I wait a minute or two, it seems like whatever lock was put on the file is released and I can delete it.
Here's some code:
sPath = Server.MapPath("/_temp/") & "\"
sFileName = Request.QueryString("filename")
Set objFile = Server.CreateObject("Scripting.FileSystemObject")
If objFile.FileExists(sPath & sFileName) Then
objFile.DeleteFile sPath & sFileName, True
End If
'Upload file occurs here
sConnectionString = "Driver={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};DBQ=" & sPath & sFileName & ";"
adLockOptimistic = 3
sSQL = "SELECT * "
sSQL = sSQL & "FROM Range"
Set rsSystem = objExcel.Execute(sSQL)
'Do stuff
rsSystem.Close
Set rsSystem = Nothing
objExcel.Close
Set objExcel = Nothing
Set objFile = Nothing
Doesn't seem to matter if I try to delete the file before or after I do the import, if I try deleting the file right after a successful import, I get the permission denied error but if I wait a minute, I'm then able to delete it.
This is an issue as users are going to be supplied templates and they may make a correction and immediately re-upload.
Any ideas as to why the lock is not getting immediately released when I close all associated objects?
Thanks!
Edit:
Changing the connection string to use a different driver seems to have done the trick, now when I close the objects I can delete the file with no issue
sConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & sPath & sFileName & ";Extended Properties=Excel 8.0;"
I've actually found a number of ways to do this.
As stated in the comments of your OP, one option is to use SSIS and import your Excel spreadsheet using a stored procedure.
You can import directly using a stored procedure
Or use a check to test whether the file is locked

Excel: Saving query results directly to CSV file

I have a dataset in Excel, of which I have to save an assorted part to a new csv file. I have used SQL to select the part required to be saved. I was hoping somebody would guide me about saving this selection to csv using SQL.
SQL gives me a recordset but I would like to loop through it only as a last resort. I am hoping there is a better approach that directly saves the entire result from within the query itself if possible.
Something like the solution by Remou on Want VBA in excel to read very large CSV and create output file of a small subset of the CSV is what I'm looking for. But unfortunately I can't get that to work.
Assuming you are in Excel VBA, has an ADODB opened with a Recordset object connected to a database and you want to save the content into a CSV (from within the Excel VBA).
The easiest is actually still by looping through the records in the recordset.
However, since you already rule that out (for whatever reasons), the next option would be to use the Recordset.Save <StreamObject> method. Create a System.IO.Streamwriter object to pass to the Recordset.Save.
OR, another way if you are using Jet SQL is:
conDB.Execute "SELECT * INTO [Text;Database=" _
& vsCSVFolder _
& ";HDR=No;FMT=Delimited].[" _
& vsCSVFileame _
& "] FROM Attendance", _
DBExport, _
adCmdText Or adExecuteNoRecords
Hope this helps.

Importing a text with separators

I am trying to automate the adding of new text files, which all have the same (known) layout.
The columns are separated using tabs (the TAB button). My question is, is it possible to do this in VBA? Like, in the access wizard for importing text files?
I am using the DoCmd.TransferText method in VBA
You'll need to go through the wizard once to make your specification file. TO do this import your text file like normal but before you get too deep into the wizard click on the bottom left, the "Advanced..." button. This is where you make your spec file.
Make ll these columns match your input file, data types and all. Be sure to select the {tab} field delimiter and the appropriate text qualifier if you are using one.
Save your spec (which can later be edited by coming back to this same screen and clicking Specs... then saving over your old one)
Now you can use in VBA like this
DoCmd.TransferText acImportDelim, "your spec name", "destination table name", sourceFilePath
There is a parameter HasFieldNames that you'll have to decide if it is true or false based on your file.
With the import wizard the downside is that for even the slightest change in file format, you'll have to click through all those steps yet again to get the import working.
Check out #Remou's answer in ms Access import table from file in a query for a way to do it in straight SQL. I am actually using the same method in a project of mine. I use something like this (see my link for the details):
insert into MyTable (column-list...)
select (column-list...)
from [data-source-specifications].[file-name]
any-other-clauses...;
Just one caveat. If you put this SQL syntax into a normal Access query object, there's a good chance that Access will mangle it to the point where it won't even be able to open the query object. So compose and save the query in a text file while you try it out in Access. Once the query is tested and working, save it in a VBA subroutine so that Access will run it exactly as is, like so:
sub MyTableImport()
sqlStr = " insert into MyTable (column-list) " ' leave a space at the
sqlStr = sqlStr & "select (column-list...) " ' end of each line of the string
sqlStr = sqlStr & "from [data-source-specifications].[file-name] "
sqlStr = sqlStr & "any-other-clauses... ;"
DoCmd.RunSQL sqlStr
end sub