I’m a newbie on here so please be gentle :)
My question is: can I get SAS (9.4 with PC Files Server) to trigger a function in MS ACCESS that imports .txt files that SAS spat out earlier?
Background: I have inherited an Access database (.accdb, using vers. 2010), which source data comes from SAS. Current method is that SAS spits out .txt files, which I (semi-manually) import into the database. Semi-manually in that there is a button/macro that imports the files but I have to open the database and press the button. I would prefer not to have to intervene at all.
I tried to skip the import of tables by using PROC EXPORT (and PC FILES SERVER) and later PROC SQL (with Access database assigned via libname) to push the data from SAS directly. However, compared to the old approach, after doing a compact and repair, the database is still about twice the size. I searched the net on how to avoid increase in size but found no answers.
I would therefore like to keep the method of SAS spitting out the .txt files but also have SAS trigger the Access function in the database that imports the files.
The button in Access activates this code:
Private Sub ImportSASDataButton_Click()
Dim Update As Byte
Update = MsgBox("Have you ran the SAS program that creates the text files?" _
, vbYesNo, "Check files have been created")
If Update = vbYes Then ImportTables
Me.CloseFormButton.SetFocus
Me.ImportSASDataButton.Enabled = False
End Sub
Which if “YES” activates this code (which is the function I wish to trigger directly):
Function ImportTables()
Dim db As Database
Dim ITables As Recordset
Set db = CurrentDb
Set ITables = db.OpenRecordset("Tables", dbOpenDynaset)
Do Until ITables.EOF
Call ImportData(ITables![TableName], _
ITables![SpecificationName], _
ITables![FileName], _
ITables![DeleteExisting], _
ITables![Use])
ITables.MoveNext
Loop
ITables.Close
End Function
There are several SAS statements that can start external programs, including
%sysexec
call system
filename pipe
Access has the command line switch /x mymacro that will run a specific macro at startup, or you can create or update the AutoExec macro that is also run automatically every time Access is started.
So your SAS code might look like
%Spit;
%sysexec msaccess /x ImportTablesMacro;
#Richard shows you how to call Access from SAS. If you do not have the ability to run command lines from your SAS session (some system administrators disable this), you can write a shell script.
First call SAS to create the .txt files.
Then call Access with the method Richard describes to run the macro.
Related
I have a pass through query built in Teradata set to export data to an Excel spreadsheet. I'm trying to automate it, but when I run the macro or open the query, a window pops up asking for the data source. I have an ODBC connection created and I'm thinking there has to be a way to make the macro pass the data source name so it will run without interaction.
Edit: Adding Macro as requested
Function AutoExec()
On Error GoTo AutoExec_Err
DoCmd.OutputTo acOutputQuery, "Performance Interval Data", "ExcelWorkbook(*.xlsx)", _
"filepath\filename.xlsx", False, "", , acExportQualityPrint
DoCmd.Quit acExit
AutoExec_Exit:
Exit Function
AutoExec_Err:
MsgBox Error$
Resume AutoExec_Exit
End Function
Couple of concerns, (can't validate any of this right now as I do not currently have access to Access for testing), but it looks like:
You're trying to OutputTo a query, to the best of my knowledge that
is not feasible.
Your file path is setup as filepath\filename.xlsx unless that is the actual location and name of your Excel sheet, something seems
wrong there to me.
I don't really think this macro relates to an ODBC of any sort in its current state.
But, you should at least start with fixing the filepath issue. That should be the full path to your Excel file and the full name of the file as well. (i.e. C:\TEMP\TestExcelSheet.xlsx)
All that being said, you may want to just go with something like this (although its a little difficult to tell if this is what you actually want or not):
'Export Excel file from Query
DoCmd.TransferSpreadsheet acExport, , "acOutputQuery", _
"C:\TEMP\TestExcelSheet.xlsx", True
NOTE: "acOutputQuery" should be the actual name of your passthrough query, "C:\TEMP\TestExcelSheet.xlsx" would be your destination path, and True adds the query's headers into the sheet, False to ignore the headers.
I need to create copies of the CurrentDB using VBA (approx. 12 copies). The copies need to be clones of the master database containing all the same forms, queries, etc. except only a limited dataset.
DoCmd.CopyDatabaseFile seems to be made for this, but only works if you are using it to copy the DB to an MS SQL Server. As MS states on their website:
Copies the database connected to the current project to a Microsoft
SQL Server database file for export.
docmd.TransferDatabase only exports the data itself, but not the structure, forms, etc.
Code I have found on the web and adapted doesn't work and throws an error on the .CopyFile line saying:
Run-time error 52: Bad file name or number
This is the code
Sub CopyDB()
Dim external_db As Object
Dim sDBsource As String
Dim sDBdest As String
sDBsource = "\\group\bsc\groups\L\BDTP\Compliance\ComplianceData\Compliance Group Reporting.accdb"
sDBdest = "\\group\bsc\groups\L\BDTP\Compliance\ComplianceData\Compliance Group Reporting_2.accdb"""
Set external_db = CreateObject("Scripting.FileSystemObject")
external_db.CopyFile sDBsource, sDBdest, True
Set external_db = Nothing
End Sub
How can I fix the above line? Alternatively is there a direct command in Access to create a copy? The "create backup" function would be tailor made for this, but I can not find it in VBA.
Looks like you have an extra quote in sDBdest accdb"""
And for database copy you can also use
FileCopy sDBsource, sDBdest
Instead of Scripting object
In a VB6 program, with an Access 2000 database, I want to read a .CSV file, with table field names in the first record, into a new Access table.
Here is my VB6 code:
With CreateObject("Access.Application")
.OpenCurrentDatabase "C:\Database1.accdb"
.DoCmd.TransferText , , newTable, importFile, True
.Quit
End With
The DoCmd.TransferText command gives me the following error:
Error # 3107 (MSAccess: Record(s) cannot be added; no insert permission on 'Table Name'.)
Any ideas what I'm doing wrong?
Seeking clarification - are you running this with block from the database you are also opening through .OpenCurrentDatabase? If so, it is my understanding that call is for opening Access from another application (MSDN), so you may be blocking yourself from editing the records. DoCmd.TransferText by itself should suffice to import the records if this scenario's assumption is true.
For future purposes note you can insert code with greater legibility by clicking the Code Sample icon or pressing Ctrl + K when writing your submission.
I have successfully created a VBS file that Windows Task Scheduler can use to export data from my database, by triggering an Access macro. Now i need to import - most steps are simple and can be achieved in the Access macro but I need to re-create table links first (field names and positions often change in the source files and it seems to mess things unless i first delete and re-create the links.)
Here's the VBA code - is there a corresponding macro action that i have missed?
'delete and recreate links to Account and Company
Dim db As DAO.Database
' Re-link the CSV Table
Set db = CurrentDb
On Error Resume Next: db.TableDefs.Delete "Contact": On Error GoTo 0
db.TableDefs.Refresh
DoCmd.TransferText TransferType:=acLinkDelim, TableName:="Contact", _
FileName:="c:\db\contact.csv", HasFieldNames:=True
db.TableDefs.Refresh
On Error Resume Next: db.TableDefs.Delete "Account": On Error GoTo 0
db.TableDefs.Refresh
DoCmd.TransferText TransferType:=acLinkDelim, TableName:="Account", _
FileName:="c:\db\account.csv", HasFieldNames:=True
db.TableDefs.Refresh
db.Close
Set db = Nothing
Yes, the macro action you missed is called Run Code.
The only caveat is that Run Code can only call VBA functions. So you can't just paste your code in the macro. Instead, you need to put it into a VBA function in an MS Access module, like this:
Public Function ReCreateTableLinks()
'delete and recreate links to Account and Company
Dim db As DAO.Database
'... paste the rest of your code here
End Function
By the way, are you saying that you are using Windows Task Scheduler, which calls a VBS file, which opens the Access database and executes the macro?
Am I understanding this correctly?
If yes: you don't need the VBS file at all if it does nothing but open the Access database.
You can just execute the Access database directly with Windows Task Scheduler.
If you name the macro autoexec, it will execute automatically when the Access database opens.
I have a program that uses a Microsoft Access database for its back-end. I need to have some VBA code (that calls a web service) execute whenever specific tables/fields are updated by the program. I see this working just like a trigger in SQL Server.
Is it possible to monitor for and act upon changes like this in Access?
Update
The program in question does not run inside of Access (i.e. not a VBA app), it simply uses an MDB file as its back-end storage. Unfortunately I don't have access to the program's code as it is a closed third party application.
This question is old, but the answers are no longer correct. Access 2010 added data macro events that can be run when data is inserted, updated or deleted. The following events are available while using either the table datasheet view or table design view (events are attached directly to table and not through the form macro button):
After Delete Macro Event
After Insert Macro Event
After Update Macro Event
Before Change Macro Event
Before Delete Macro Event
More information is located here:
https://msdn.microsoft.com/en-us/library/office/dn124692.aspx
https://support.office.com/en-us/article/Create-a-data-macro-b1b94bca-4f17-47ad-a66d-f296ef834200
Access the GUI environment vs Jet the database format are separate things.
If you are using an Access database as a backend - it's just the JET functionality you can work with. Access the GUI (which includes VBA) runs on the client machine and there is no automated trigger functionality.
If your program is the only program using the Access file, then it should know when a table is being updated and execute some code in place of a trigger.
Otherwise, you need another application/service running all the time that is checking the access file tables for updates (maybe you have some update_date type of field on your tables?).
When an Access database file gets written to, it's date/time stamp changes. I suppose you could try using a file monitor to detect changes to the file, and then examine the file to see what has changed.
It would help if the Access database has LastModified date/time columns in the tables.
If you are using Jet (i.e. the data is stored in an MDB file back end) then the only places you can run code would be in the After Update Event in a Form. The problem here of course is if the data is changed without using the form then the event will not fire.
If you are using MS Access 2003 then to run a Web Service you can download the Microsoft Office 2003 Web Services Toolkit Click Here to download
If you are stuck in VBA it gets a little rough. One way to go would be to have a form with timer in it (you could have it open invisibly. The timer could check the table, say once a minute (or whatever interval seems suitable) for changes in record count, and verify the table still exists. (code below)
But personally this isn't what I would recommend that you do. Access is notorious for corruption. When used as a simple back end you are fairly safe most of the time, but to have it running a monitor, means the file is always open. This is basically playing Russian Roulette with your database. At minimum I would link to your database from another Access file and monitor the linked tables, that way if your monitor crashes, you don't take the production DB with you. Finally, make sure that you don't query too often, as I'd hate to see you be the sole cause of the website timing out:)
Option Explicit
Private m_lngLstRcrdCnt_c As Long
Private Sub Form_Open(Cancel As Integer)
Const lngOneMinute_c As Long = 60000
Me.TimerInterval = lngOneMinute_c
End Sub
Private Sub Form_Timer()
Const strTblName_c As String = "Foo"
Const strKey_c As String = "MyField1"
Dim rs As DAO.Recordset
Dim lngRcrdCnt As Long
If TableExists(strTblName_c) Then
Set rs = CurrentDb.OpenRecordset("SELECT Count(" & strKey_c & ") FROM " & strTblName_c & ";", dbOpenSnapshot)
If Not rs.EOF Then lngRcrdCnt = Nz(rs.Fields(0&).Value, 0&)
rs.Close
If lngRcrdCnt <> m_lngLstRcrdCnt_c Then
m_lngLstRcrdCnt_c = lngRcrdCnt
'Number of records changed, do something.
End If
Else
'Table is deleted, do something.
m_lngLstRcrdCnt_c = -1
End If
End Sub
Private Function TableExists(ByVal name As String) As Boolean
Dim tdf As DAO.TableDef
On Error Resume Next
Set tdf = CurrentDb.TableDefs(name)
If LenB(tdf.name) Then 'Cheap way to catch broken links.
Set SafeGetTable = tdf
End If
End Function