I export my msaccess queries sql code for source versioning. I have been doing this for a while, but just now noticed an inconsistency. The exported sql code was different from the code I would get from navigating to the SQL view in Design Mode. It would be an older version. My export code boils down to this:
Dim db As Database
Dim qr As QueryDef
Dim arq_out As Integer
Set db = CurrentDb
arq_out = FreeFile
arq_name = "Querydefs.sql"
Open destPath & arq_name For Output As arq_out
For Each qr In db.QueryDefs
If Not qr.Name Like "~TMP*" Then
Print #arq_out, qr.Name
Print #arq_out, qr.sql
Print #arq_out, String(70, "-")
End If
Next qr
The current database is one I had not used for more than a year.
You may understand better with this timeline:
Updated a few queries (long time ago). The update consisted of renaming some queries and then adjusting accordingly downstream.
Exported SQL query code with above VBA (today).
Noticed that a certain queryA's sql was weirdly using its dependency's old name.
Opened queryAin design view and it showed the dependency's correct name. Different from what was exported. So I closed without saving.
Ran Compact & Repair before exporting again with the same VBA.
queryA had the correct code exported.
Noticed some queryB in the same database had a similar "obsolete" problem.
Same as 4, 5 and 6.
So it seems MsAccess stores it's SQL somewhere else and is feeding me an old or cached version. I do not even know if I regressed some relevant change due to this wrench in my workflow, as I use it ad-hoc for data analysis as a work limitation.
I tried querying the system tables to see if those held the correct SQL, but ran into the same issue. They would show me the old dependencies and be automatically updated after I opened the design view. I used the following sample query:
SELECT MSysQueries.Name1, MSysObjects.Name
FROM MSysQueries INNER JOIN MSysObjects ON MSysQueries.ObjectId = MSysObjects.Id
WHERE (((MSysQueries.Name1)="Dependency_Old_Name"));
I would appreciate help to either: get the actual sql code from MsAccess or force MsAccess to update all QueryDefs.SQL.
Opening and closing the queries in design view would not be the preferred solution, as it sometimes introduces spurious as Expr1. But it may well be the solution if nothing else is possible.
Related
The general idea was to create a VBA script that effectively write SQL SELECT queries for users that don't have experience with SQL. It accepts from a database that they're already familiar with. The ultimate goal is to allow users to:
Select what columns they would like to see.
Make simple restrictions on them (date range, specific part numbers)
Order this list however they would like.
I have written (in VBA) a script to do so, but I have one remaining issue. I can't execute SELECT queries directly in VBA. I also can't find any information on how to export the completed query from VBA back into the Access Database. I've considered writing to a text file, then having Access read from said text file, using a macro, and importing the query, but it does not appear that Access support such a functionality..
Any help would be greatly appreciated.
Dim sql_ as String
sql_ = "SELECT * FROM Table"
DoCmd.RunSQL sql_
Dim sql_ as String
sql_ = "UPDATE Table SET Field = 'ABC'"
CurrentDb.Execute sql_, dbFailOnError
Here is how I would tackle this myself:
Write the VBA to build the SQL string (which you've done)
Create a data connection to your Access DB (Data > Get External Data > From Access)
Use VBA to change the command text in the data connection properties, then refresh.
This should enable you to dynamically build SQL, query the DB and return the results to Excel in a table.
Hope that helps!
this is my first time posting a question here, but I almost always get good answers from searching this site. I'm trying to find out if there is a better way to speed up this process I have of writing a table column in Access to a .txt file. Here is the code I have, which works, but it's on the slow side. It takes about 45s to write around 7000 items.
lsFileName2 = "E:\DOI_Inventory2\SyncData\EquipUser.txt"
LiFileNumb = FreeFile
SysCmd acSysCmdSetStatus, "Updating User Equipment List"
Open lsFileName2 For Output As LiFileNumb
With rst
Do While Not .EOF
Write #LiFileNumb, ![EqUserFile]
.MoveNext
Loop
End With
dbs.Close
Close LiFileNumb
I'm fairly new to the IT field so any help would be greatly appreciated. Thanks
Just to add a note, the actual query is fine. I already checked that and it's pretty fast.
Create a query, save it with a name, and then use TransferText to export the query's data to your text file.
So assuming you have a SELECT query named qryExportMe like this which returns your table's column data correctly ...
SELECT EqUserFile
FROM YourTable;
... refer to this TransferText example and adapt it to fit your needs.
DoCmd.TransferText TransferType:=acExportDelim, _
Tablename:="qryExportMe", _
FileName:="E:\DOI_Inventory2\SyncData\EquipUser.txt", _
HasFieldNames:=True
Check the TransferText options at that linked page or from Access' built in help system.
Note you are not required to include the option names. I added them to help you keep track of which is which.
If this approach speeds up your export operation adequately, I think it will be because Access handles the task as a single set-based file write. Your recordset approach required Access to process one row at a time ... and one reason such approaches are called RBAR (row by agonizing row) is because they are often painfully slow.
I have a MS Access 2010 application that is linked to MS SQL 2008 in the back end.
When I run the application, I encounter a run-time error '2467' - The expression you entered refers to an object that is closed or doesn't exists.
When I select Debug, the line points to:
Forms!FRM_MAIN_HOME!FRM_SUB_EDIT.Form.RecordSource =
I've run the query in the SSMS and works fine.
I've looked for missing references, and there aren't any.
When I run the application with Shift to present the forms, I get a different error: Data Type mismatch in criteria expression. This time I don't have a debug option, but I suspect that this is the real issue.
One more thing: when I run this application on a different database, it loads with no errors.
Any help is much appreciated.
Thanks.
Forms!FRM_MAIN_HOME!FRM_SUB_EDIT.Form.RecordSource = _
"SELECT V.VendorNumber, V.VendorName, T.DocumentNumber, " _
& "T.DocumentDate, T.AmountInc, T.GSTClaim, T.GSTBatch " _
& "FROM TBL_VENDOR_MASTER AS V INNER JOIN TBL_GST_01_TRANSACTIONS AS T " _
& "ON V.AAVendorID = T.AAVendorID WHERE T.GSTBatch =" _
& Me.BATCH_NUM & " ORDER BY V.VendorName"
When I run this code in the SSMS, it works just fine. Also, when I select a different database, it works without any errors.
I am prepared to bet you are running this in the wrong event. You cannot use the Open event to refer to controls on a form. I am not sure why you are dynamically setting the subform recordsource.
The recordsource should be:
SELECT V.VendorNumber,
V.VendorName,
T.DocumentNumber,
T.DocumentDate,
T.AmountInc,
T.GSTClaim,
T.GSTBatch
FROM TBL_VENDOR_MASTER AS V
INNER JOIN TBL_GST_01_TRANSACTIONS AS T
ON V.AAVendorID = T.AAVendorID
ORDER BY V.VendorName
You should set the link fields like so:
Link child field : GSTBatch
Link master field : BATCH_NUM
The issue seems to be related to some memory issues as the tables are quite large (and my machine is not the fastest...), but the error messages that appeared while MS Access is running (every time I click on a field, a tab, or anything really, I'd get the same error, just without the Debug option), is related to a table I have that MS Access didn't like one of the fields I had there.
To troubleshoot this error, I loaded an older backup, and started updating some columns and testing MS Access, until I found the problem. Also, I added some indexes, and changed the default time-out for ODBC to 0 (unlimited) in the registry.
That seemed to fix this problem.
I am running a SSIS package to load say a million rows from a flat file, which uses a script task for complex transformations and a SQL Server table destination. I am trying to figure out the best way (well, ANY way at this stage) to write out to a different table the row count (probably in multiples of 1000 to be more efficient) DURING the data flow processing. This is so that I can determine the percentage of progress throughout a task that might take a few minutes, simply by querying the table periodically.
I can't seem to add any SQL task into the flow, so I'm guessing the only way is to connect to the SQL database inside the .NET script. This seems painful and I'm not even sure it is possible. Is there another more elegant way? I've seen reference to "Rows Read" performance counter but not sure where I access this in SSIS and still not sure how to write it to a SQL table during the Data Flow processing.
Any suggestions appreciated.
Glenn
there are two easy options here:
Option 1: use the built-in logging with SSIS and watch the on progress event. this can be configured to log to several different outputs including relational database and flat files
See more Here
Option 2: you could add a SSIS script component that could fire off notifications to an external system like a database table
I recently solved this in a slightly different manner, which I find superior to using scripting and opening separate connections in code to DBs:
In the source query or a transform shape, add a row count (incremental)
In a conditional branching, use a modulo expression (%) to branch whenever the number is a multiple of for example 1000, but this could be configurable or based on source data (for example 0.0% to 100.0% of the data)
Create a log connection manager and use a destination. Control the batching sizes so that rows are immediately committed to the target table.
Why not write a .NET application and you can integrate into that to get information as to where the SSIS package is at.
Basically everything that is sent to the console you can get, and there are event handlers you can attach to to get information while it is processing the package.
Here is a link that may help you to go with this approach:
http://www.programminghelp.com/database/sqlserver/sql-server-integration-services-calling-ssis-package-in-c/
OK, had some success at last.... added a call to the following sub in the script component:
Sub UpdateLoadLog(ByVal Load_ID As Int32, ByVal Row_Count As Int32, ByVal Row_Percent As Int32, ByVal connstr As String)
Dim dbconn As OleDbConnection
Dim Sql As String
Dim dbcomm As OleDbCommand
dbconn = New OleDbConnection(connstr)
dbconn.Open()
Sql = "update myTable set rows_processed = " & Row_Count & ", rows_processed_percent = " & Row_Percent & " where load_id = " & Load_ID & " and load_log_type = 'SSIS'"
dbcomm = New OleDbCommand(Sql, dbconn)
dbcomm.ExecuteNonQuery()
dbconn.Close()
dbconn = Nothing
dbcomm = Nothing
End Sub
This gets executed every 1000 rows, and successfully updates the table. The row already existed as it gets created in the control flow at the start of the package, and updated again in the control flow at the very end with final rowcount and 100%.
Thanks for all your suggestions guys.
Is the application consuming the row count a .net application? When it comes to sharing information between applications there are a lot of accepted practices. May be you should take a look in to them. And for your particular case, if it is .net application that consumes this row number for calculating progress, may be you can store the information some place else other than a DB table, like file system, web service, windows environment variables, log (like windows events log), etc are some that came to my mind now. I think updating a windows environment variable with row count form with in your script component will be a good enough solution. Just like using a global variable to share data between two functions inside a program. :)
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