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
Related
I am trying to write the user name who is currently logged in to records in the table X that is used to update table Y with new records from it.
Here is the code I use:
Private Sub UPD_Click()
On Error GoTo Err_UPD_Click
DoCmd.TransferDatabase acImport, "Microsoft Access", "D:\Working\Test.mdb", acTable, "tblTest", "tblTest_Import", False
DoCmd.RunSQL "ALTER TABLE tblTest_Import ADD COLUMN [CreatedBy] Text(25);"
Dim myDB As Database
Set myDB = CurrentDb
myDB.Execute "UPDATE tblTest_Import " _
& "SET [tblTest_Import].[CreatedBy] = [Forms]![frmLogin]![txtUserName];"
myDB.Execute "INSERT INTO tblMain(Year, CreatedBy)"_
& "SELECT tblTest_Import.Year, tblTest_Import.CreatedBy " _
& "FROM tblTest_Import " _
& "WHERE (((Exists (SELECT * FROM tblMain " _
& "WHERE tblMain.ID = tblTest_Import.ID))=False));"
Exit_UPD_Click:
Exit Sub
Err_UPD_Click:
MsgBox Err.Description
Resume Exit_UPD_Click
End Sub
Form frmLogin stays open but hidden (Me.Visible = False).
The problem is the field CreatedBy in tblTest_Import does not get updates and Access returns this message: "Too few parameters. Expected 1." And none of lines in the code gets highlighted.
I tried to add
Dim frmLogin As Form
Set frmLogin = Screen.ActiveForm
but it didn't help.
What is wrong with my code?
I found solution :)
I just needed to add several quotes to this part of code
myDB.Execute "UPDATE tblTest_Import " _
& "SET [tblTest_Import].[CreatedBy] = '" & [Forms]![frmLogin]![UserName] & "';"
Bingo!
I was asked to capture the date when a specific field is updated , so I created an event to update the record of that field.
Dim db As Database
Dim strSQL As String
Dim LDate As String
LDate = Format(Date, "yyyy-mm-dd")
Set db = CurrentDb
strSQL = "UPDATE [Lotinfo] " & _
"SET [PriorityChanged] = " & _
Chr(34) & LDate & Chr(34) & _
" where [BKPO#] = " & _
Chr(34) & Forms![LotTabFrm]![LotInfoPriority]![BKPO#] & Chr(34) & _
" and [ModelNo] = " & _
Chr(34) & Forms![LotTabFrm]![LotInfoPriority]![ModelNo] & Chr(34)
DoCmd.SetWarnings False
DoCmd.RunSQL strSQL
DoCmd.SetWarnings True
The update does happen, however it keeps showing a 'copy to clipboard' message box asking me to drop the changes or copy to clipboard and in both cases the changes are lost
Is there a way to stop that message box from showing up?
You are getting this message because Ms Access has a conflict. Should it save the values you entered into the form or rather the values you are entering now using the UPDATE statement?
Assuming that you want the values from the UPDATE statement, add the following line before the UPDATE to save the Form values first:
DoCmd.RunCommand acCmdSaveRecord
I want to apply an SQL query to one Access table, from which it is retrieving data from a table in another Access file. I've looked around on this subject and can't seem to get solutions to work.
Based on this source http://support.microsoft.com/kb/113701, I came up with the following, but still have no luck.
sSQL = "UPDATE TableInCurrentDB
SET [Field1InCurrentDB]= DAvg('Field1InExternalDB','[;database=C:\VB\ExternalDB.accdb].[TableInExternalDB]','Field2InExternalDB= & Year(Now()) & ')
WHERE [Field2InCurrentDB]='1';"
DoCmd.RunSQL sSQL
I know that the error lies somewhere in the reference to the external DB, because the code works fine if the tables are in the same database. However, it's tough to tell exactly what's wrong because the error I get is 'Unknown'.
How can I modify this statement to update an Access table from another Access database's table?
You prefer not to use a link to the table in the external database, but that choice is a complication when you want to use DAvg. However, since you're doing this with VBA code, you can ditch DAvg and do what you need in 2 steps:
First retrieve the average from the external table.
Use that step #1 average in your UPDATE.
For step #1, test this as a new query in the Access query designer ...
SELECT Avg(Field1InExternalDB)
FROM TableInExternalDB IN 'C:\VB\ExternalDB.accdb'
WHERE Field2InExternalDB=Year(Date());
Assuming that query returns the correct value, adapt your VBA code to retrieve the same value.
Dim db As DAO.database
Dim strSelect As String
Dim varAvg As Variant
strSelect = "SELECT Avg(Field1InExternalDB)" & vbCrLf & _
"FROM TableInExternalDB IN 'C:\VB\ExternalDB.accdb'" & vbCrLf & _
"WHERE Field2InExternalDB=Year(Date());"
'Debug.Print strSelect
Set db = CurrentDb
varAvg = db.OpenRecordset(strSelect)(0)
Debug.Print Nz(varAvg, 0) ' see note
Note that query will return Null when no rows include Field2InExternalDB values which match the current year. That is why varAvg is declared as Variant. Later Nz(varAvg, 0) will give you zero instead of Null.
Then you can use a parameter query for your UPDATE and supply Nz(varAvg, 0) as the parameter value.
Dim qdf As DAO.QueryDef
Dim strUpdate As String
strUpdate = "UPDATE TableInCurrentDB" & vbCrLf & _
"SET [Field1InCurrentDB]=[pAvg]" & vbCrLf & _
"WHERE [Field2InCurrentDB]='1';"
'Debug.Print strUpdate
Set qdf = db.CreateQueryDef(vbNullString, strUpdate)
qdf.Parameters("pAvg") = Nz(varAvg, 0)
qdf.Execute dbFailOnError
Set qdf = Nothing
Set db = Nothing
Could you not do this as a single step? Incorporate the output of the first SQL as the input to the "set" in the second?
In other words,bypass the first query and just do the second using this as the "strUpdate" string:
strUpdate = "UPDATE TableInCurrentDB" & vbCrLf & _
"SET [Field1InCurrentDB]=" & vbCrLf & _
" (SELECT Val(Nz(Avg(Field1InExternalDB),0))" & vbCrLf & _
" FROM TableInExternalDB IN 'C:\VB\ExternalDB.accdb'" & vbCrLf & _
" WHERE Field2InExternalDB=Year(Date()) )" & vbCrLf & _
"WHERE [Field2InCurrentDB]='1';"
After I edit information and change the information and click update, it gives me a error. I tried the parenthesis brackets no luck.
Too few parameters Expected 1. Run time error '3061'
Private Sub cmdUpdate_Click()
Dim strSql As String
strSql = "UPDATE PlantTransaction " & _
"SET TransactionID=" & Me.txtTranID & _
",[Plant Number]='" & Me.txtPlantNo & "'" & _
",TransactionDate=#" & Me.txtTransDate & "#" & _
",Opening_Hours='" & Me.txtOpeningHRS & "'" & _
",Closing_Hours='" & Me.CloseHrs & "'" & _
",Fuel='" & Me.txtFuel & "'" & _
",[Fuel Cons Fuel/Hours]='" & Me.txtFuelConsFuelHr & "'" & _
",[Hour Meter Replaced]='" & Me.txtHrMtrRep & "'" & _
",Comments='" & Me.txtComments & "'" & _
",[Take on Hour]='" & Me.txtTOH & "'" & _
" WHERE TransactionID=" & Me.PlantTransactionQuery.Form.Recordset.Fields("Tr ansactionID")
Debug.Print strSql ' <- prints to Immediate window
CurrentDb.Execute strSql, dbFailOnError
cmdClear_Click
Me.PlantTransactionQuery.Form.Requery
End Sub
You were smart to include this line in your code:
Debug.Print strSql ' <- prints to Immediate window
Now when you get the missing parameter message, go to the Immediate window (you can use Ctrl+g to go there) and copy the SQL statement.
Then create a new Access query in the query designer, switch to SQL View, and paste in the text you copied. When you attempt to run that query, Access will present a parameter input box which includes the name of whatever it thinks is the parameter.
Compare that parameter name with the field names in your data source. Often this situation occurs because the query includes a misspelled field name. Another possibility with an UPDATE is that one of the values you're trying to update is unquoted text. Regardless of the cause, the parameter name from that input box should help you track it down. Show us the actual text from that UPDATE statement if you need further help.
Any time that you "glue together" a long SQL statement with lots of user input you face the challenges of
correctly delimiting strings and dates,
escaping delimiters within such fields (usually quotes inside a text field), and
getting all of the required commas in the right places
You can avoid those annoyances by using a Recordset to perform the update:
Dim rst As DAO.RecordSet
Set rst = CurrentDb.OpenRecordset("PlantTransaction", dbOpenDynaset)
rst.FindFirst "TransactionID=" & Me.PlantTransactionQuery.Form.Recordset.Fields("Tr ansactionID")
If Not rst.NoMatch Then
rst.Edit
rst!TransactionID = Me.txtTranID
rst![Plant Number] = Me.txtPlantNo
rst!TransactionDate = Me.txtTransDate
rst!Opening_Hours = Me.txtOpeningHRS
rst!Closing_Hours = Me.CloseHrs
rst!Fuel = Me.txtFuel
rst![Fuel Cons Fuel/Hours] = Me.txtFuelConsFuelHr
rst![Hour Meter Replaced] = Me.txtHrMtrRep
rst!Comments = Me.txtComments
rst![Take on Hour] = Me.txtTOH
rst.Update
End If
rst.Close
Set rst = Nothing
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.