I have two backend databases. BE-Main and BE-User.
I want to export the data from one table in BE-User (save as file in disk) and import it in BE-Main using VBA. Since the BE-Main is the main one and the BE-User is secondary, I need to fill up data if ID is existing and add new ID (row) if ID doesn't exist.
Export part
DoCmd.TransferDatabase acExport, "Microsoft Access", ExtDb, acTable, "tblHealth", "tblHealth1", False
If I use the same code with import, access is making a new table because it exists.
Any idea how to Update/Refresh data in the table? Tables has a primary key (heathID) which I might can use with SQL.
An easier route might be to link the table and run your queries from there. They might be the same name to the coding below will allow you to change the name of the linked table.
Public Sub ExportImportData()
'Create the link table
DoCmd.TransferDatabase _
TransferType:=acLink, _
DatabaseType:="Microsoft Access", _
DatabaseName:="YourDatabaseLocationAndName.accdb", _
ObjectType:=acTable, _
Source:="TargetTableName", _
Destination:="LinkTableName"
'Updates data
CurrentDb.Execute "UPDATE YourUpdateTableName " & _
"SET YourUpdateTableName.FieldName = LinkTableName.FieldName " & _
"WHERE(((YouUpdateTableName.ID) = LinkTableName.ID));"
'Add more fields if updating multiple fields
'Appends new data
CurrentDb.Execute "INSERT INTO YourUpdateTableName ( List out all fields ) " & _
"SELECT List Out all fields " & _
"FROM LinkTableName;"
'Deletes link table
DoCmd.DeleteObject acTable, "LinkTableName"
End Sub
YourDatabaseLocationAndName = example: "C:\Users\username\desktop\MyDatabase.accdb"
targetTableName = The name of the table in the backend you are linking from
LinkTableName = a name given to your new linked table
Related
I have a database that has been working well for a couple years until this morning. When I attempt to copy the contents of a remote table into a local backend, I am presented with an err: "Error 3622 - You must use the dbSeeChanges option..."
The remote table is on a server and does have an AutoNumber attribute. The backend table is a simple readonly/static snapshot that does not care about the auto numbering datatype and is defined simply as Number - I just need the table (snapshot) to be local for performance concerns.
I added the dbSeeChanges variable without success - complains about "Too few Parameters" on the db.execute line (below).
Here are some details from my db:
Dim db As Database
dim strSQL as string
Set db = CurrentDb()
strSQL = "INSERT INTO Item " & _
"SELECT dbo_Item.* " & _
"FROM dbo_Item " & _
"WHERE dbo_Item.MASTER_INVID= " & TempVars!my_InvID
db.Execute strSQL, dbFailOnError + dbSeeChanges
What am I missing? Any suggestions to avoid/correct.
Another way to do this is to make a copy of the linked table then covert that to a local table:
localTableName = "Item"
DoCmd.CopyObject , localTableName , acTable, "dbo_Item"
DoCmd.SelectObject acTable, localTableName , True
RunCommand acCmdConvertLinkedTableToLocal
I have researched the code for this online for weeks but still cannot find what I need so any help will be greatly appreciated:
I need to:
1) Import the first CSV in "C:\Documents" and create a table called "Data" with import specs I have already created.
2) Create and export all fields in a (SELECT?) query (Sport = Football, Event = Match Odds) to an excel binary file called "Match Odds 001"
I then wish to delete the data contained in this query from the Table "Data".
3) Repeat step 2) two hundred times with different Events exporting each query to an excel binary file with the name "(Event) 001" then deleting that query data from the table.
4) After all queries have run and been deleted, any remaining data in the table will be exported to an excel binary file named "Misc 001" and then this data deleted from the Table "Data" (or maybe even delete the Table "Data" completely.)
5) Repeat from 1) importing the 2nd CSV file from "C:\Documents" and exporting queries to Excel Binary files named "(Event) 002" so as not to replace the previous files.
This would continue until all CSVs have been imported and split.
As there are 200 queries I'd prefer to create them in VBA code.
I have just started using VBA in Access and so far have found code which will import all csv files in a folder so I am hoping to insert code to create, export then delete the queries.
Any help on the vba coding required is hugely appreciated.
.
.
UPDATE: With massive thanks to Mike I now have the following code but a few small issues have surfaced.
1) How can I compact the Database to reduce the filesize after the "DoCmd.RunSQL "DROP TABLE Data"" command?
I wish to repeatedly import 500MB CSV's then delete them so after I import and drop the first then import the second the filesize becomes 1GB and is increasing.
2) How difficult is it to include a second column in the Events Table so that my SELECT query becomes WHERE Event=Event & Selection=Selection and to combine both these fields to create the filename?
3) The Events Table used to create the Queries and file names sometimes contains characters that cannot be used in file names, for Example "/" & "?". Can these be easily dropped to create the filenames or might it be better to add a further column to the Events Table which would contain the filename to be used (ie a combination of Event and Selection but with the disallowed characters removed)
If I can solve these issues I will have the perfect code for my needs, again with all credit to Mike.
Sub ImportAndSplit()
Dim fileCounter As String
Dim rs As New ADODB.Recordset
Dim sql As String
Dim qdf As QueryDef
Dim file As String
Const strPath As String = "C:\Users\Robbie\Documents\Data\" 'Directory Path
Dim strFile As String 'Filename
Dim strFileList() As String 'File Array
Dim intFile As Integer 'File Number
strFile = Dir(strPath & "*.csv") 'Loop through the folder & build file list
While strFile <> ""
intFile = intFile + 1 'add files to the list
ReDim Preserve strFileList(1 To intFile)
strFileList(intFile) = strFile
strFile = Dir()
Wend
If intFile = 0 Then 'see if any files were found
MsgBox "No files found"
Exit Sub
End If
DoCmd.SetWarnings False
Set qdf = CurrentDb.QueryDefs("Export")
sql = "SELECT Event FROM Events"
rs.Open sql, CurrentProject.Connection, adOpenStatic, adLockReadOnly
For intFile = 1 To UBound(strFileList) 'cycle through the list of files & import to Access creating a new table called Data
DoCmd.TransferText acImportDelim, "Data", "Data", strPath & strFileList(intFile)
fileCounter = Format(intFile, "000") 'format i so that when you use it in file names, the files sort intuitively
Do While Not rs.EOF
sql = "SELECT * FROM Data WHERE Event='" & rs!Event & "'" 'select the records to export and export them
file = "C:\Users\Robbie\Documents\Data Split\" & rs!Event & " " & fileCounter & ".xlsb" 'use the counter to distinguish between which csv your exporting from
qdf.sql = sql
DoCmd.TransferSpreadsheet acExport, acSpreadsheetTypeExcel12, qdf.Name, file
sql = "DELETE FROM Data WHERE Event='" & rs!Event & "'" 'delete the records from the source table
DoCmd.RunSQL sql
rs.MoveNext
Loop
rs.MoveFirst
'export remaining data
file = "C:\Users\Robbie\Documents\Data Split\Misc " & fileCounter & ".xlsb" 'use the counter to distinguish between which csv your exporting from
sql = "SELECT * FROM Data"
qdf.sql = sql
DoCmd.TransferSpreadsheet acExport, acSpreadsheetTypeExcel12, qdf.Name, file
'delete remaining data
'DoCmd.RunSQL "DELETE FROM Data"
'or delete the table
DoCmd.RunSQL "DROP TABLE Data"
Next
MsgBox UBound(strFileList) & " Files were Imported and Split"
rs.Close
DoCmd.SetWarnings True
End Sub
Create a table with your Events in it (in my example it's called "Events" and has one field "Event").
Create a query called "Export". Doesn't matter what it does, we're going to overwrite it 200 times anyway.
Add the ActiveX Data Objects Library reference
Code:
Dim i As Integer
Dim fileCounter As String
Dim rs As New ADODB.Recordset
Dim sql As String
Dim qdf As QueryDef
Dim file As String
DoCmd.SetWarnings False
Set qdf = CurrentDb.QueryDefs("Export")
sql = "SELECT Event FROM Events"
rs.Open sql, CurrentProject.Connection, adOpenStatic, adLockReadOnly
For i = 1 To x 'where x is however many csvs you're importing
fileCounter = Format(i, "000") 'format i so that when you use it in file names, the files sort intuitively
'run your import code here
Do While Not rs.EOF
'select the records to export and export them
sql = "SELECT * FROM Data WHERE Event='" & rs!Event & "'"
file = "C:\Documents\" & rs!Event & fileCounter & ".xlsb" 'use the counter to distinguish between which csv your exporting from
qdf.sql = sql
DoCmd.TransferSpreadsheet acExport, acSpreadsheetTypeExcel12, qdf.Name, file
'delete the records from the source table
sql = "DELETE FROM Data WHERE Event='" & rs!Event & "'"
DoCmd.RunSQL sql
rs.MoveNext
Loop
rs.MoveFirst
'export remaining data
file = "C:\Documents\MISC" & fileCounter & ".xlsb" 'use the counter to distinguish between which csv your exporting from
sql = "SELECT * FROM Data"
qdf.sql = sql
DoCmd.TransferSpreadsheet acExport, acSpreadsheetTypeExcel12, qdf.Name, file
'delete remaining data
DoCmd.RunSQL "DELETE FROM Data"
'or delete the table
'DoCmd.RunSQL "DROP TABLE Data"
Next i
rs.Close
DoCmd.SetWarnings True
Make sure none of those files exist before running this, it will not overwrite files. Either delete them manually or you could use the Windows Script Host in the loop to delete the files if they exist before creating them...
Dim fso As New FileSystemObject
If fso.FileExists(file) Then
fso.DeleteFile (file)
End If
In response to your updates:
Consider linking them instead of importing (DoCmd.TransferText acLink, "Data"...). I don't believe it's possible to compact while you're working in a db, it would have to close.
You basically answered your own question. If you want to do that, add the column to the table and update the SQL exactly how you said.
You could use the Replace function but you'd have to run it for each illegal character and you might end up missing one. It's probably best to do what you suggested and just create them yourself in a new column.
I have linked the sql server tables to ms access so that I can use ms access as the front end.I was able to access the tables from access, until I run into an error ODBC call failed when I tried to open one of the tables. There was no problem with the other tables. Actually I have changed a column name in sql server after creating a link. Is this the problem? I am really worried about this as I was about to use access as a front-end for my future purposes.
When you link to a remote table, Access stores metadata about that table. When you later change the table structure, the metadata doesn't get updated to capture the change.
Delete the link. Then recreate the link. That way the metadata will be consistent with the current version of the table.
Yes changing the column name after linking the table is most likely causing your failure. Is it is now trying to pull data from a column that no longer exists. You will need to relink the table. You can programatically link tables in access. We do that in may of our access applications and drive the tables that need to be linked from a local access table.
Public Sub LinkODBCTables()
Dim objRS As DAO.Recordset
Dim objTblDef As DAO.TableDef
Dim strTableName As String
Dim strAliasName As String
Dim strDSN As String
Dim lngTblCount As Long
Set objRS = CurrentDb.OpenRecordset( _
" select TableName," & _
" AliasName," & _
" DSN," & _
" DatabaseName," & _
" Development_DSN," & _
" UniqueIndexCol" & _
" from tblODBCLinkedTables " & _
" order by TableName", dbOpenSnapshot)
While Not objRS.EOF
' Check to see if we already have this linked tableDef
' We don't care if it is not actually in there
strTableName = objRS.Fields("TableName")
If Not IsNull(objRS.Fields("AliasName")) Then
strAliasName = objRS.Fields("AliasName")
Else
strAliasName = strTableName
End If
If DEV_MODE Then
strDSN = objRS.Fields("Development_DSN")
Else
strDSN = objRS.Fields("DSN")
End If
On Error Resume Next
CurrentDb.TableDefs.Delete strAliasName
If Err.Number <> 0 And _
Err.Number <> 3265 Then ' item not found in collection
Dim objError As Error
MsgBox "Unable to delete table " & strAliasName
MsgBox Err.Description
For Each objError In DBEngine.Errors
MsgBox objError.Description
Next
End If
On Error GoTo 0
Set objTblDef = CurrentDb.CreateTableDef(strAliasName)
objTblDef.Connect = g_strSQLServerConn & _
"DSN=" & strDSN & _
";DATABASE=" & objRS.Fields("DatabaseName") & _
";UID=" & g_strSQLServerUid & _
";PWD=" & g_strSQLServerPwd
objTblDef.SourceTableName = strTableName
On Error Resume Next
CurrentDb.TableDefs.Append objTblDef
If Err.Number <> 0 Then
Dim objErr As DAO.Error
For Each objErr In DBEngine.Errors
MsgBox objErr.Description
Next
End If
On Error GoTo 0
' Attempt to create a uniqe index of the link for updates
' if specified
If Not IsNull(objRS.Fields("UniqueIndexCol")) Then
' Execute DDL to create the new index
CurrentDb.Execute " Create Unique Index uk_" & strAliasName & _
" on " & strAliasName & "(" & objRS.Fields("UniqueIndexCol") & ")"
End If
objRS.MoveNext
Wend
objRS.Close
End Sub
We are using a single SQLServer login for our access applications so the g_strSQLServerUID and g_strSQLServerPwd are globals that contain that info. You may need to tweek that for your own needs or integrated security. We are setting up two DSNs one for production and the other for development. The DEV_MODE global controls wich set of DSNs are linked. You can call this code from a startup macro or startup form. It will deleted the old link and create a new link so you always have the most up to date schema.
I have a query reside in a access file(.mdb), I would like to call this query in VBA, and store the result into a existing table. The previous content of the table should be deleted before the result was inserted.
Any idea? In my existing code, the query name "genInboundCdr" was execute via DoCmd.TransferSpreadsheet and result was stored into a excel file.
Private Sub BtnExecuteQuery_Click()
If IsNull(txtOutputPath.value) Then
MsgBox "Please enter a valid output file location."
Else
If ObjectExists("Query", "genInboundCdr") Then
strPathToSave = txtOutputPath.value
MsgBox "About to extract inbound cdr..." & vbCrLf & _
"Please notice that the query may take longer time " & _
"( > 20 minutes ) if the linked tables contains a lot " & _
"of records."
txtStatus.value = txtStatus.value & _
"About to extract inbound cdr..." & vbCrLf & _
"Please notice that the query may take longer time " & _
"( > 20 minutes ) if the linked tables contains a lot " & _
"of records." & vbCrLf
DoCmd.TransferSpreadsheet acExport, _
acSpreadsheetTypeExcel9, _
"genInboundCdr", _
strPathToSave, _
True
MsgBox ("Inbound Cdr generated.")
txtStatus.value = txtStatus.value & "Inbound Cdr generated." & vbCrLf
Else
MsgBox ("Query does not exist! Please review your steps.")
End If
End If
End Sub
The easiest thing to do is execute a delete query on the destination table and then use an append query.
A delete query's SQL looks like this:
DELETE *
FROM foo2;
An append query's SQL likes like this:
INSERT INTO foo_dest ( f0, f1, f2, f3 )
SELECT foo_src.f0, foo_src.f1, foo_src.f2, foo_src.f3
FROM foo_src;
The SELECT portion would be your source query (genInboundCdr).
You can execute either one of these query in VBA like this:
DoCmd.RunSQL = "insert into ..."
or
Currentdb.execute = "insert into ..."
or if you prefer to use stored queries
DoCmd.OpenQuery "genInboundCdr"
(there may be another way to run genInboundCdr, but I can't recall right now)
I end up doing like this:
1) query and store the result into a excel file.
2) import the excel file using transferspreadsheet.
DoCmd.TransferSpreadsheet acExport, _
acSpreadsheetTypeExcel9, _
"genInboundCdr", _
strPathToSave, _
True
DoCmd.TransferSpreadsheet acImport, _
acSpreadsheetTypeExcel9, _
"temp_result", _
strPathToSave, _
True
I am new to Access. I have a table full of records. I want to write a function to check if any id is null or empty. If so, I want to update it with xxxxx.
The check for id must be run through all tables in a database.
Can anyone provide some sample code?
I'm not sure if you are going to be able to find all tables in the database with Access SQL. Instead, you might want to write up some VBA to loop through the tables and generate some SQL for each table. Something along the lines of:
update TABLE set FIELD = 'xxxxxx' where ID is null
Check out the Nz() function. It leaves fields unaltered unless they're null, when it replaces them by whatever you specify.
For reasonable numbers and sizes of tables, it can be quicker to just
open them
sort by each field in turn
inspect for null values and replace manually
It's good practice to find out where the nulls are coming from and stop them - give fields default values, use Nz() on inputs. And have your code handle any nulls that slip through the net.
I'm calling it the UpdateFieldWhereNull Function, and shown is a Subroutine which calls it (adapted from http://www.aislebyaisle.com/access/vba_backend_code.htm)
It updates all tables in the DbPath parameter (not tested, handle with care):
Function UpdateFieldWhereNull(DbPath As String, fieldName as String, newFieldValue as String) As Boolean
'This links to all the tables that reside in DbPath,
' whether or not they already reside in this database.
'This works when linking to an Access .mdb file, not to ODBC.
'This keeps the same table name on the front end as on the back end.
Dim rs As Recordset
On Error Resume Next
'get tables in back end database
Set rs = CurrentDb.OpenRecordset("SELECT Name " & _
"FROM MSysObjects IN '" & DbPath & "' " & _
"WHERE Type=1 AND Flags=0")
If Err <> 0 Then Exit Function
'update field in tables
While Not rs.EOF
If DbPath <> Nz(DLookup("Database", "MSysObjects", "Name='" & rs!Name & "' And Type=6")) Then
'UPDATE the field with new value if null
DoCmd.RunSQL "UPDATE " & acTable & " SET [" & fieldName & "] = '" & newFieldValue & "' WHERE [" & fieldName & "] IS NULL"
End If
rs.MoveNext
Wend
rs.Close
UpdateFieldWhereNull = True
End Function
Sub CallUpdateFieldWhereNull()
Dim Result As Boolean
'Sample call:
Result = UpdateFieldWhereNull("C:\Program Files\Microsoft Office\Office\Samples\Northwind.mdb", "ID", "xxxxxx")
Debug.Print Result
End Sub