I am new to using VBA scripts in Access db.
I have a grandfathered db which has the following snippet
Dim My_Selected_Pool() As String
Dim My_Selected_Scenario() As String
DoCmd.SetWarnings False
DoCmd.OpenQuery "Dist_Cons1", , acReadOnly
I have looked around everywhere but I am unable to locate Dist_Cons1. This query creates tables and populates it after processing some other existing tables in the database. When I use debug option it doesn't step into the query either.
Related
I am trying to change the links in an Access 2016 database, but the method I've used in the past is not working as required.
I am using the
t.connect="new connection"
t.refreshlink
method, where t is a the table.
I have seen in the linked table manager that the tables are now grouped by a data source. I can create the new source and link it to the desired table, but I have many as migrating, so would like to do this in code.
I get no errors the current way, but immediately after the .refreshlink the table's .connect is still the same.
Is this still possible?
I currently populate a dictionary with the table name and it's existing connection, but only if non ODBC.
I am then looping through this dictionary, getting the table and changing its connection
CurrentDb.TableDefs(strTableName).Connect = strNewConnection
CurrentDb.TableDefs(strTableName).RefreshLink
Debug.Print CurrentDb.TableDefs(strTableName).Connect
Existing connection = ;DATABASE=\\app01\Access\CRM_Data.mdb
New connection =;DATABASE=C:\CRM_TEST\CRM_DATA_BE_2016.accdb
Many thanks
You should not use CurrentDb.TableDefs when changing tables, as that changes between calls and makes the reference to the tabledef where you change the connection string be a different one than the one where you refresh the link.
Dim d As DAO.Database
Set d = CurrentDb
d.TableDefs(strTableName).Connect = strNewConnection
d.TableDefs(strTableName).RefreshLink
AFAIK this behaviour is not version-dependent, so the code you provided should never have worked.
I am using this code in Access 2016 and it works just fine:
Public Function RelinkTables(environment As Integer)
On Error Resume Next
Dim tblDef As DAO.TableDef
For Each tblDef In CurrentDb.TableDefs
If tblDef.Connect <> "" Then
tblDef.Connect = GetConnectionString(environment)
tblDef.RefreshLink
End If
Next
End Function
Public Function GetConnectionString(environment As Integer) As String
Select Case environment
Case 1 ' connection to Test db
GetConnectionString = "your connection string to Test"
Case 2 ' connection to Prod db
GetConnectionString = "your connection string to Production"
End Select
End Function
If this would not work with your db than may be the path is wrong.
I spent alot of time to create 24 different separate MS Access queries that I have saved in the MS Access database. They have to be run in a specific order.
I want to run a macro that will just execute them one after another.
I know I can do this using VBA but I have copy all the SQL into VBA one at a time.
is there a way I can just have VBA run the saved queries in the MS Access database without copying them into VBA?
I am very good with SQL. 15+ years doing Oracle work, Code writing, DB Tuning, Data DBA work.
I am new to using SQL and VBA to run against MS Access DB.
To clear a few terminologies:
MS Access GUI comprises of five main object types: tables, queries, forms, macros, and modules. Technically, there is no such thing as VBA macros in MS Access. This is a terminology from MS Excel where each subroutine is defined as a macro.
In MS Access there is a physical object known as a macro which is divorced from VBA (though can call VBA code). Coded routines which includes all functions and subroutines in MS Access are encapsulated in the module (object) usually behind forms, reports, or standalone modules.
Do remember each Microsoft Office application maintains its own object library and should not be conflated with one another. VBA itself is a separate component installed by default (see Tools \ References in IDE). Any language (Java, PHP, Python, etc.) that can run COM-interfacing can connect and run each Office app's object library. VBA is simply one type that does this.
MS Access maintains stored queries (as another object) which can be actions queries (UPDATE, INSERT even CREATE TABLE or ALTER TABLE) or recordset queries (SELECT). You do not have to copy all of SQL code inside VBA to run these saved query objects. In fact, stored queries run more efficiently than string queries called in code since the MS Access engine compiles the best execution plan with stored queries.
Having said that, consider a macro calling multiple OpenQuery actions or coded subroutine inside a module calling multiple DoCmd.OpenQuery commands
Macro
OpenQuery
QueryName: myfirstActionQuery
View: Datasheet
Data Mode: Edit
OpenQuery
QueryName: mySecondActionQuery
View: Datasheet
Data Mode: Edit
OpenQuery
QueryName: myThirdActionQuery
View: Datasheet
Data Mode: Edit
...
For action queries you do not have to close the query as OpenQuery runs process without physically opening anything to screen. You may want to incorporate the SetWarnings to False action in order to avoid the message prompt of how much records will be updated or inserted which is a default setting in Access. Because this is a potentially hazardous action, click Show All Actions to see this specific action.
Module
Public Sub RunQueries()
DoCmd.SetWarnings False
DoCmd.OpenQuery "myfirstSavedQuery"
DoCmd.OpenQuery "mySecondSavedQuery"
DoCmd.OpenQuery "myThirdSavedQuery"
...
DoCmd.SetWarnings True
End Sub
Similar to macros, you do not have to close action queries and can call the DoCmd.SetWarnings to suppress the message prompts with each update, insert, or make-table action.
The alternative to turning SetWarnings off and on is #LeeMac's solution which runs queries using the DAO's Database.Execute() command. In fact, because DAO is part of the MS Access object library, the above method can be run outside VBA as mentioned above.
Python
import os
import win32com.client
access_file = r'C:\Path\To\MyDatabase.accdb'
try:
oApp = win32com.client.Dispatch("Access.Application")
oApp.OpenCurrentDatabase(access_file)
db = oApp.Currentdb()
db.Execute("myFirstSavedQuery")
db.Execute("mySecondSavedQuery")
db.Execute("myThirdSavedQuery")
...
except Exception as e:
print(e)
finally:
oApp.Quit()
db = None; oApp = None
del db; del oApp
In its very simplest form, you can define a Sub such as:
Sub ExecuteQueries()
With CurrentDb
.Execute "MyQuery1"
.Execute "MyQuery2"
'...
.Execute "MyQueryN"
End With
End Sub
Or define this as a Function in a public module if you intend to invoke this from an MS Access Macro.
Here is another method if you don't have specific naming conventions utilizing an array for the query names in execution order:
Public Sub RunMasterUpdate()
Dim qryList As Variant
Dim i As Long
qryList = Array("QueryName1", "QueryName2", "QueryName3")
For i = LBound(qryList) To UBound(qryList)
CurrentDb.Execute qryList(i)
Next
End Sub
You can do something like this to run saved queries:
Dim db As DAO.Database, qry As DAO.QueryDef
Set db = CurrentDb
Debug.Print "-- Start --"
For Each qry In db.QueryDefs
If qry.Name Like pattern Then
Debug.Print qry.Name,
qry.Execute
Debug.Print "(" & qry.RecordsAffected & ")"
End If
Next
Debug.Print "-- End --"
db.Close()
Name the queries so that the alphabetical order matches the the expected execution order, e.g., 01_deleteCustomers, 02_appendCustomers, 03_etc.
Specify a pattern string or remove the If alltogether if you want to run all the queries.
Note that in the Visual Basic editor under menu Tools > References... I have selected Microsoft DAO 3.6 Object Library. (You might have another version)
I want to export from SQL to an MS-Access database.
I DO NOT want to link to SQL Server.
Successful with export using the SQL Import/Export wizard, but this is cumbersome and time consuming and I want to automate the process through SQL Code.
I am willing to use BCP, but have yet to figure out "HOW"
You can use the transfer database command.
eg:
Sub TestTrans()
Dim strLocalTable As String
Dim strSQLTable As String
Dim strSQLDataBase As String
strSQLDataBase = "test3"
strLocalTable = "tblFood2"
strSQLTable = "tblFood2"
Dim strODBC As String
strODBC = "ODBC;DRIVER=SQL Server;SERVER=ALBERTKALLAL-PC\SQLEXPRESS;Trusted_Connection=Yes;DATABASE="
strODBC = strODBC & strSQLDataBase
DoCmd.TransferDatabase acImport, "ODBC Database", strODBC, acTable, strSQLTable, strLocalTable
End Sub
So the above will transfer a single table. If you not using a trusted connection like above, then you can add ;UID=Albert;PASS=MYPASSWORD
Edit
Of course the above code is run inside of Access. Reading your question again, I see you may well want to do this from SQL server side, and not necessary inside of Access.
I can't seem to find any good reference or example of how to get this to work. I have a database which is stored on an AS/400 (my local MS Access database [stored on a network drive] has linked tables to the 400, using ODBC/DSN). My utility works just fine passing SQL statements to through Access to retrieve data from the 400 using the linked tables. The problem is that with some of the larger reports and the fact that the 400 is several states away, it can take several hours to run the reports. The settled on solution to this is to create a local "copy" of the tables needed with just the data set that is relevant to the reports, which is a considerably smaller data set. Obviously this has the down side of not being "live" data but I can live with that. Ultimately what I want to do is gather the relevant data from the linked table and save it to separate database that is local to the client so that it could be used if offsite/offline and to increase the speed of the report.
network location stored database = DB1 (Tabled linked to AS/400)
local client stored database = DB2 (relevant data set created by below SQL, non-linked tables named the same as the linked tables)
Below is the SQL statement that I'm trying to get to work using VBA & DAO
SELECT
DB1_TABLEA.FIELD1,
DB1_TABLEA.FIELD2,
DB1_TABLEA.FIELD3,
DB1_TABLEA.FIELD4,
DB1_TABLEA.FIELD5,
DB1_TABLEA.FIELD6,
DB1_TABLEA.FIELD7,
DB1_TABLEA.FIELD8
INTO
DB1_TABLEA IN 'Local_DB_Copy.accdb' <== Creating non-linked copy
FROM
DB1_TABLEA
WHERE
(
((DB1_TABLEA.FIELD4) Like 99999)
AND
((DB1_TABLEA.FIELD6)="02" Or (DB1_TABLEA.FIELD6)="22")
)
;
I already have my program working fine and returning/processing data from the AS/400 DB. I just need to be able to get the above to work so that people have the option to run a local copy that will process much faster.
Below is the code that I tried, but of course it fails or I wouldn't be here.
Sub gCreateLocalDBTables()
Dim DBPath As String
Dim LocalDBPath As String
Dim sSQL As String
Dim DB As DAO.Database
Dim DB2 As DAO.Database
Dim RS As DAO.Recordset
LocalDBPath = "AS400_Local.accdb"
sSQL = "SELECT DB1_TABLEA.FIELD1, DB1_TABLEA.FIELD2, DB1_TABLEA.FIELD3, DB1_TABLEA.FIELD4, DB1_TABLEA.FIELD5, DB1_TABLEA.FIELD6, DB1_TABLEA.FIELD7, DB1_TABLEA.FIELD8 INTO DB2_TABLEA IN '" & LocalDBPath & "' FROM DB1_TABLEA WHERE (((DB1_TABLEA.FIELD4) Like 99999) AND ((DB1_TABLEA.FIELD6)='02' Or (DB1_TABLEA.FIELD6)='22'));"
Set DB = OpenDatabase(LocalDBPath, False, False)
DB.TableDefs.Delete ("DB2_TABLEA")
DB.Close
DBPath = Interaction.GetSetting("Cust_Tools", "Settings\Report_Planning", "400DB_Location")
Set DB2 = OpenDatabase(DBPath, False, False)
Set RS = DB2.OpenRecordset(sSQL)
RS.Close
DB2.Close
Set RS = Nothing
Set DB = Nothing
Set DB2 = Nothing
End Sub
I know the SQL works as I have tested it from inside MS Access. I just can't find info on how to get it to work being passed from Excel VBA
You cannot assign an action query like a make-table query (i.e., SELECT with INTO call) to a recordset. Consider executing your DROP and SELECT ... INTO action queries prior to opening recordset on the local table. Also, it is unclear why you are opening a second database or what the path points to. Below opens a recordset on the mainframe data:
Set DB = OpenDatabase(LocalDBPath, False, False)
DB.Execute "DROP TABLE DB2_TABLEA", dbFailOnError
DB.Execute sSQL, dbFailOnError
Set RS = DB.OpenRecordset("SELECT * FROM DB2_TABLEA")
Furthermore, the IN clause in your make-table query is unnecessary as you are currently connected to the very database you are running the action on. Simply remove it ('" & LocalDBPath & "'). Also, LIKE expressions without wildcards and on numbers should be replaced with =
SELECT
DB1_TABLEA.FIELD1,
DB1_TABLEA.FIELD2,
DB1_TABLEA.FIELD3,
DB1_TABLEA.FIELD4,
DB1_TABLEA.FIELD5,
DB1_TABLEA.FIELD6,
DB1_TABLEA.FIELD7,
DB1_TABLEA.FIELD8
INTO
DB2_TABLEA
FROM
DB1_TABLEA
WHERE
(
((DB1_TABLEA.FIELD4) = 99999)
AND
((DB1_TABLEA.FIELD6)='02' OR (DB1_TABLEA.FIELD6)='22')
)
;
In fact, consider saving the query inside the MS Access database (Ribbon -> Create -> Query Design -> SQL View) and call it as a named object and avoid any long SQL in VBA.
DB.Execute "DROP TABLE DB2_TABLEA", dbFailOnError
DB.Execute "mySavedQuery", dbFailOnError
Set RS = DB.OpenRecordset("SELECT * FROM DB2_TABLEA")
I have this VBA code below, which runs on open of a form in MS Access. This code is meant to delete all records from several tables, and then run saved append queries (that are quite complex) to fill in those tables once again, with fresh data every time.
The form that opens (after this code runs) is based on the last table that gets updated in the code sequence (PDSForecast), and I have confirmed that the append query for that table works and loads the correct data in.
The issue though is, when the form based on that table is opened (which triggered this code to run in the first place), all the records show up as #Deleted for some reason, even though the append query that populates the table this form is based on is the last piece of code that runs before the form opens, and it works. Can someone help me understand what I'm doing wrong here?
Thanks!
Private Sub Form_Open(Cancel As Integer)
DoCmd.SetWarnings False
DoCmd.RunSQL "DELETE FROM ECIInventTransIntentDim"
DoCmd.RunSQL "DELETE FROM CurrentOH"
DoCmd.RunSQL "DELETE FROM CurrentOO"
DoCmd.RunSQL "DELETE FROM RequirementsAXAPTA"
DoCmd.RunSQL "DELETE FROM AvgWeeklyUsage"
DoCmd.RunSQL "DELETE FROM PDSForecast"
DoCmd.OpenQuery "Query_ECIINVENTTRANSINVENTDIM"
DoCmd.OpenQuery "Query_CURRENTOH"
DoCmd.OpenQuery "Query_CURRENTOO"
DoCmd.OpenQuery "Query_REQUIREMENTSAXAPTA"
DoCmd.OpenQuery "Query_AVGWEEKLYUSAGE"
DoCmd.OpenQuery "Query_PDSFORECAST"
DoCmd.SetWarnings True
End Sub
It sounds like your form is bound to the data table. What you should do is unbind the form before the series of queries are run and then re-bind. Your code will look similar to this:
frmMain.DataSource = nothing
DoCmd.SetWarnings False
DoCmd.RunSQL "DELETE ..."
... etc.
DoCmd.SetWarnings True
frmMain.DataSource = "myTable"