Run query in the background - ms-access

I have a database which I'm working on. It is composed of split database, both front and multiple links to backend tables.
I am working on a report which is composed of 15 different sub-reports. I have a form which allows me to input start date and end date for the report. There's a button which generates the final report. The problem is when I want to generate the report, I would have to re-run each of the different make-table queries for each of the sub-reports. The issue with this is that there would be 2 warnings for each query, one to delete my table and another for rows added to the table.
I researched online and found this code to run the Execute command which will remove all the warnings. I'm new to VB but I figured I'll give it a try and I get the following run-time error "3078: The MS Access database engine cannot find the input table or query". I checked the query name and it matches so I'm not sure why I'm getting this error. I've only tried one of the 15 queries so I can make sure it works. Once I get this to work, my other question is would combining all these into 15 execute commands work in the module?
Private Sub PS_Report_Date_AfterUpdate()
Dim dbs As DAO.Database
Dim lngRowsAffected As Long
Dim lngRowsDeleted As Long
Dim sql$
sql = "[qry_Maui_Division_KWH_Produced]"
Set dbs = CurrentDb
' Execute runs both saved queries and SQL strings
dbs.Execute sql, dbFailOnError
' Get the number of rows affected by the Action query.
' You can display this to the user, store it in a table, or trigger an action
' if an unexpected number (e.g. 0 rows when you expect > 0).
lngRowsAffected = dbs.RecordsAffected
dbs.Execute "DELETE FROM tbl_Maui_Division_KWH_Produced WHERE Bad", dbFailOnError
lngRowsDeleted = dbs.RecordsAffected
End Sub
SQL Code:
SELECT
tbl_MPP_DailyGenerationReport.DateLog,
[MPP_Daily_Gross_Gen_kWh]+[Total_Gross_kWh] AS Maui_Gross_kWh_Produced,
[Total_Aux]+[Total_Aux_kWh] AS Maui_Gross_Aux_kWh_Produced, [MPP_Daily_Gross_Gen_kWh]-[Total_Aux]+[Total_Net_kWh] AS Maui_Net_kWh_Produced,
Round(([Total_MBTU_Burned]*1000000)/([MPP_Daily_Gross_Gen_kWh]+[Total_Gross_kWh]),0) AS Maui_Gross_BTU_kWh,
Round([Total_MBTU_Burned]*1000000/([MPP_Daily_Gross_Gen_kWh]-[Total_Aux]+[Total_Net_kWh]),0) AS Maui_Net_BTU_kWh,
Round(([MPP_Daily_Gross_Gen_kWh]+[Total_Gross_kWh])/[Total_Barrels_Burned],0) AS Maui_Gross_kWh_BBL,
Round(([MPP_Daily_Gross_Gen_kWh]-[Total_Aux]+[Total_Net_kWh])/[Total_Barrels_Burned],0) AS Maui_Net_kWh_BBL
INTO tbl_Maui_Division_KWH_Produced
FROM ((tbl_MPP_DailyGenerationReport
INNER JOIN tbl_KPP_DailyGenerationReport
ON tbl_MPP_DailyGenerationReport.DateLog = tbl_KPP_DailyGenerationReport.DateLog)
INNER JOIN tbl_MPP_Aux_DailyGenerationReport
ON tbl_MPP_DailyGenerationReport.DateLog = tbl_MPP_Aux_DailyGenerationReport.DateLog)
INNER JOIN qry_Maui_Total_Fuel_Burned
ON tbl_MPP_DailyGenerationReport.DateLog = qry_Maui_Total_Fuel_Burned.DateLog
WHERE (((tbl_MPP_DailyGenerationReport.DateLog)=[Forms]![Power Supply Reports]![PS_Report_Date]));​

This will run your queries without warnings:
Private Sub PS_Report_Date_AfterUpdate()
DoCmd.SetWarnings False
DoCmd.OpenQuery "qry_Maui_Division_KWH_Produced"
DoCmd.RunSQL "DELETE FROM tbl_Maui_Division_KWH_Produced WHERE Bad"
DoCmd.SetWarnings True
End Sub

Related

Speed Up Moving data from Oracle 11 to MySQL using MS Access

I have a little problem with downloading data from Oracle DB and moving it to the MySQL table.
On Oracle i have only a read privilege. The only task I could execute is Select.
On MySQL i have select/insert/update privilege. Also, there's no problem to change anything in mysql structure - i also have access to mysql root.
Each week I have to download huge amount of data from Oracle and move it to MySQL (for further processing). The best (and the only) solution in my case is to use MS Access.
My vba code snippet looks like (code is usually put into a loop, where I perform some inserts, each for different business site. Executing it in one query sometimes meet no end).
Public Sub DownloadData()
On Error GoTo ErrorTrans
DoCmd.SetWarnings False
Dim strWhere1 As String, strWhere2 As String, strQueryName As String
Dim qdDaneObrRabE As QueryDef, qdDaneObrRabTmp As QueryDef
Dim cnADO As ADODB.Connection
DoCmd.OpenQuery ("qryDaneObrRabCzysc") 'Calling truncate data procedure on mysql table
Set cnADO = CurrentProject.Connection
cnADO.CommandTimeout = 300 '5 minut
Set qdDaneObrRabE = CurrentDb.QueryDefs("qryDaneObrRabE")
strQueryName = "tmpObroty_" & GenerateHash(8)
Set qdDaneObrRabTmp = CurrentDb.CreateQueryDef(strQueryName, "select * from table2;") 'this select is just dummy statement, replaced some lines below
qdDaneObrRabTmp.Connect = qdDaneObrRabE.Connect
qdDaneObrRabTmp.SQL = Replace(qdDaneObrRabE.SQL, "{WHERE1}", strWhere1)
qdDaneObrRabTmp.SQL = Replace(qdDaneObrRabTmp.SQL, "{WHERE2}", strWhere2)
cnADO.Execute "INSERT INTO mysqltable SELECT * FROM " & strQueryName & ";"
Call QueryDefsCleanUp("tmpObroty_")
Call MsgBox("Success")
Set cnADO = Nothing
Exit Sub
ErrorTrans:
Call ActivityLog(Environ("USERNAME"), Now, "DownloadData", True, Err.Number, Err.Description)
End Sub
Please let me know if executing these types of inserts via ADODB is good.
I also tested DAO but i don't see difference.
All of used tables/querydefs are linked tables or pass-through querydefs.

Access: Update query with list of users

I have an access db with some tables, queries, macro... etc
One table is a result of a query and it's used to populate a sharepoint. This table has a column [User] that has no records but I would like to fill with a list of users before upload to the sharepoint.
Ex. the table has 58 rows and I whant to use the 10 users.
Row1 - User 1
Row2 - User 2
...
Row10 - User 10
Row11 - User 1
and so on...
I realy don't know what is the best way to do this.
Can anyone help me? Thanks.
I would suggest using Visual Basic for Applications (VBA) for this.
Create a new Module and then create a procedure that will populate the data.
Its relatively simple - you want to loop through all the users and update the parent table.
For my code, I am assuming that you have one table holding your query results (with the empty "User" field), and that you have another table holding all of your users (using the field name "UserName")
Public Sub PopulateUsers()
Dim dbs As DAO.Database
Dim rstUsers As DAO.Recordset
Dim rstComputers As DAO.Recordset
' Open up our tables
Set dbs = CurrentDb
Set rstUsers = dbs.OpenRecordset("Users")
' If there are no users then complain and quit
If rstUsers.EOF Then
rst.Close
MsgBox "There are no users to populate", vbInformation, "Error"
Set rstUsers = Nothing
Exit Sub
End If
Set rstComputers = dbs.OpenRecordset("ComputerUsers")
' Loop through all of our computer records
Do Until rstComputers.EOF
rstComputers.Edit
rstComputers!User = rstUsers!UserName
rstComputers.Update
rstUsers.MoveNext
If rstUsers.EOF Then
rstUsers.MoveFirst
End If
rstComputers.MoveNext
Loop
' Close tables
rstUsers.Close
rstComputers.Close
' Clear object references to free up memory
Set dbs = Nothing
Set rstUsers = Nothing
Set rstComputers = Nothing
debug.print "Users Populated"
End Sub
You can press Control + G to open the immediate window and then type "PopulateUsers".

Copy Access database query into Excel spreadsheet

I have an Access database and an Excel workbook.
What I need to do is query the database and paste the query into a worksheet.
The issue is Runtime. I have stepped throught the program and everything works, but it works extremely slow, we're talking up to 30 second run times per query, although most of this run time is coming with the CopyFromRecordset call.
The database has over 800k rows in the table I'm querying.
Currently at my company there are people every morning who manually query the tables and copy and paste them into excel. I'm trying to remove this process.
Here is what I have:
Sub new1()
Dim objAdoCon As Object
Dim objRcdSet As Object
' gets query information '
Dim DataArr()
Sheets("Data2").Activate
DataArr = Range("A1:B40")
For i = 1 To UBound(DataArr)
job = DataArr(i, 1)
dest = DataArr(i, 2)
If InStr(dest, "HT") > 0 Then
OpCode = "3863"
ElseIf InStr(dest, "HIP") > 0 Then
OpCode = "35DM"
End If
strQry = "SELECT * from [BATCHNO] WHERE ([BATCHNO].[Job]='" & job & "') AND ([BATCHNO].[OperationCode] = " & "'" & OpCode & "')"
Set objAdoCon = CreateObject("ADODB.Connection")
Set objRcdSet = CreateObject("ADODB.Recordset")
objAdoCon.Open "Provider = Microsoft.Jet.oledb.4.0;Data Source = C:\Users\v-adamsje\Desktop\HTmaster.mdb"
'long run time
objRcdSet.Open strQry, objAdoCon
'very long run time
ThisWorkbook.Worksheets(dest).Range("A2").CopyFromRecordset objRcdSet
Set objAdoCon = Nothing
Set objRcdSet = Nothing
Next i
End Sub
Any help is appreciated. I am new to VBA and Access so this could be an easy fix. Thanks
Excel is very good at getting data for itself, without using VBA.
On the DATA ribbon
create a connection to a table or view of data somewhere (eg mdb or SServer)
then use the "existing connections" button to add data from your connected table to a worksheet table (ListObject).
You can even set the workbook (ie connection) to refresh the data every 12 hours.
Repeat for all the tables /view you need to grab data for. You can even specify SQL as part of the connection.
Let excel look after itself.
I just grabbed a 250,000 row table from a "nearby" disk in 2 secs.
It will look after itself and has no code to maintain!
I don't see how the CopyFromRecordset can be improved. You could copy the recods programmatically (in VB) record-by-record but that will probably be slower than the CopyFromRecordset.
You can move the CreateObject statements out of the loop, With the connection and RecordSet already created, this could be faster:
Set objAdoCon = CreateObject("ADODB.Connection")
Set objRcdSet = CreateObject("ADODB.Recordset")
For i = 1 To UBound(DataArr)
...
next i
Set objRcdSet = Nothing
Set objAdoCon = Nothing
You could also try ADO instead of DAO. ADO seems to perform faster on large record sets.
But also the server could be an issue, for example, are there indexes on Job and OperationCode? If not, then the slowness could be the server selecting the records rather than Excel placing them in the worksheet.
Whelp, never found out why the CopyFromRecordset runtime was obsurd, but solved my problem by pulling the whole table into excel then into an array, looping through that and putting them in respective sheets. From 30min runtime to <1min

access 2010 bloat with forms based on pass through queries

My access 2010 database has super massive bloat. It has gone from 44mb to 282mb in just a few runs of the VBA. Here is what I have set up:
Local tables - these calculate statistics on forms and generally don't move around too much.
Pass through queries - my personal suspect. While viewing a form, if the user clicks on a record I run a pass through query using the record the user clicked on. So user clicked on "joe", pass through query runs with sql string = "select * from sqlserver where name= " &[forms]![myform]![firstname]
After this query runs, my vba DELETES the pass through query, then recreates it after another record is selected. so the user goes back to the list of names, and clicks BRIAN. then my vba deletes the pass through query and creates another one to select all records named brian from sql server, using the same code as above.
Forms - my forms are using the pass through queries as sources.
Is what I'm doing not very smart? How can I build this better to prevent access from exploding in file size? I tried compact and repair, as well as analyze DB performance in access 2010. Any help at all is appreciated, I've been googling access2010 bloat and have read about temptables as well as closing DAO (which I am using, and which I did explicitly close). Thanks!
Here is some code for 1 of the forms i'm using -
Private Sub name_Click()
'set dims
Dim db As DAO.Database
Dim qdExtData As QueryDef
Dim strSQL As String
Dim qdf As DAO.QueryDef
'close form so it will refresh
DoCmd.Close acForm, "myform", acSaveNo
'delete old query so a new one can be created with the same name
For Each qdf In CurrentDb.QueryDefs
If qdf.Name = "QRY_PASS_THROUGH" Then
DoCmd.Close acQuery, "QRY_PASS_THROUGH", acSaveNo
DoCmd.SetWarnings False
DoCmd.DeleteObject acQuery, "QRY_PASS_THROUGH"
DoCmd.SetWarnings True
Exit For
End If
Next
Set db = CurrentDb
'sql for the data
strSQL = "select fields from (table1 inner join table2 on stuff=stuff and stuff=stuff) left join table3 on stuff=stuff and stuff=stuff where flag='P' and table.firstname = " & [Forms]![myform]![firstname]
Set qdExtData = db.CreateQueryDef("QRY_PASS_THROUGH")
'how you connect to odbc
qdExtData.Connect = "ODBC;DSN=server;UID=username;PWD=hunter2;"
qdExtData.SQL = strSQL
DoCmd.OpenForm ("names")
Forms!returns!Auto_Header0.Caption = "Names for " & Me.name & " in year " & Me.year
qdExtData.Close
db.Close
qdf.Close
Set db = Nothing
Set qdf = Nothing
End Sub
There no reason I can think of to not bind the form to a view and use the “where clause” of the open form command. It would eliminate all that code.
You could then simply use:
strWhere = "table.FirstName = '" & me.FirstName & "'"
Docmd.OpenForm "Names”,,,strWhere
Also, it makes little or no sense that a C + R does not return free space. Something else here is seriously wrong.
Also, you really don’t need to delete the query each time. Just assume that the pass-through ALWAYS exists and then use this:
strSQl = “your sql goes here as you have now”
Currentdb.Querydef("MyPass").SQL = strSQL
Docmd.Openform “your form”
The above is all you need. I count about 3 lines of code here that will replace all what you have now. Note that of course the connection string info is saved with the pass-though and does not need to be set or messed with each time.
I would also do a de-compile of your database. I have a short cut setup on all my dev machines so I can just right click to de-compile. Here is some info on de-compile:
http://www.granite.ab.ca/access/decompile.htm
So really, I don’t know why you not using the where clause of the open form? Just bind the form to a SQL view without any conditions. Then use the open form command – you only pull records down the network pipe that match your criteria.
And note how you can stuff your SQL directly into the .SQL property of the query def as above shows – again no need for that delete code and this also means you don’t mess with connection info in code either. Again about 3 lines in total.

DCount then OpenForm query in Access 2007 too slow

I have a number of buttons on a form which provide additional information to the user, each using DCount to see if there is any information to display and if so, opening a popup form to display it. All had been working well but now for one particular button, it is taking anything between 30 seconds and a minute to open the popup form, which is obviously unacceptable. Can't understand why it worked fine originally but has now gone so slow. All the other buttons still open their form in under a second. VBA is:
Private Sub btnNotes_Click()
'open the popup notes for the current record, if there are associated records
If DCount("ID","qlkpIDForNotes") = 0 Then
MsgBox "There are no notes for this patient", vbOKOnly, "No information"
Else
DoCmd.OpenForm "fsubNotes",,,"ID = " & Me.displayID
End If
End Sub
The table being queried has approx 40,000 rows, where the largest table checked for the other buttons has about 12,000. Have tried doing the DCount directly on the table rather than through a query, but doesn't make any difference. Also tried taking out a section of the data from the original table, copying about 1100 rows into a new table and testing on that. It still took 12 seconds to open.
Any ideas, anyone?
Using DCount() just to find out if there are any row in the table or query can be rather inefficient since DCount() will have to run the whole query and go through all records to return the total count just so you can compare that to 0.
Depending on the complexity of that query, and the joins in it, and whether the joins use fields that have indexes or not, the cost of having to run that query can be exponentially proportional to the number of records in the underlying tables.
To solve your issue try this:
make sure there is an index on the underlying table's ID field in the qlkpIDForNotes query, and that all fields used in the JOIN or WHERE clauses also have indexes.
check if you can use the main underlying table or use a simplified query just to test if there are records that may be returned by qlkpIDForNotes, in short, you may not need to run that query in full just to find out if it would have some records.
use a separate function such as HasAny() below instead of DCount() when you only need to find out if a query returns any results:
'-------------------------------------------------------------------------'
' Returns whether the given query returned any result at all. '
' Returns true if at least one record was returned. '
' To call: '
' InUse = HasAny("SELECT TOP 1 ID FROM Product WHERE PartID=" & partID) '
'-------------------------------------------------------------------------'
Public Function HasAny(ByVal selectquery As String) As Boolean
Dim db As DAO.database
Dim rs As DAO.RecordSet
Set db = CurrentDb
Set rs = db.OpenRecordset(selectquery, dbOpenForwardOnly)
HasAny = (rs.RecordCount > 0)
rs.Close
Set rs = Nothing
Set db = Nothing
End Function
With this, you can simply rewrite your code as :
Private Sub btnNotes_Click()
'open the popup notes for the current record, if there are associated records '
If Not HasAny("qlkpIDForNotes") Then
MsgBox "There are no notes for this patient", vbOKOnly, "No information"
Else
DoCmd.OpenForm "fsubNotes",,,"ID = " & Me.displayID
End If
End Sub