I'm attempting to setup a simple function to add the computer name of the person who adds a record into an access database. For example if user on computer 12345 creates a new record into table tblTasks then in the field "Owner" it would put that persons computer name.
The way I'm going about this currently (And not sure it's the best way) is, on the form under the field "Owner" I have set the Default value to =owner and I have created the following function:
Function Owner()
Dim cdb As DAO.Database, rst As DAO.Recordset
Dim wshNet As Object
Set wshNet = CreateObject("Wscript.Network")
Set cdb = CurrentDb
Set rst = cdb.OpenRecordset("SELECT * FROM tblTasks", dbOpenDynaset)
rst.AddNew
rst!Owner = wshNet.Computername
rst.Update '<---- Error starts here
Set wshNet = Nothing
End Function
I'm getting the following error when creating a new record:
I know part of the issue is to do with a validation rule I created not allowing a record to be created without a Task Name but I want to keep that in place.
I'm thinking the issue of the "Owner" field giving an #Error is also to do with the fact that instead of using a button action to create a record I am keeping the ability to just add from the bottom of the record. Which I'd also like to keep in tact.
Any help or advice would be greatly appreciated!
Thanks!!
-Deke
I worked on something similar a few days ago and started using the fields like you. I found a solution similar to the macro that you have.
Create a macro event for the form's BeforeInsert property. Use the below code for the macro and update to fit your needs.
Private Sub Form_BeforeInsert(Cancel As Integer)
Dim Owner As String
Owner = Environ("COMPUTERNAME")
Me!AddedBy= Owner
End Sub
EDIT
Regarding the error that you're receiving, I'm not sure if this will help, but try defining Owner as
Dim wshNet As String
Set wshNet = Environ("COMPUTERNAME")
TL;DR ---------------
If I properly declare the variables in the initialisation script, I can't attach to the "connection" objects of a SAPFEWSELib.GuiApplication .
The collection MyApplication.Children(0), is empty but if I comment out the declaration block, it just works !?
TL;DR ---------------
I am trying to create a more reliable connection between my SAP client and my excel application.
My current issue is with the establishing of the connection. The SAP client provides a sample vbscript when using its script recording function.
If Not IsObject(MyApplication) Then
Debug.Print "yep"
Set SapGuiAuto = GetObject("SAPGUI")
Set MyApplication = SapGuiAuto.GetScriptingEngine
End If
If Not IsObject(Connection) Then
Set Connection = MyApplication.Children(0)
End If
If Not IsObject(session) Then
Set session = Connection.Children(0)
End If
This other question on stackoverflow came close to answer, but fell short
stackoverflow.com/questions/24738998/vba-using-variables-that-were-not-declared
The original code is here, I have modified slightly so it would work in excel/vba.
(I dropped the IsObject(Wscript) and I had to replace Application with MyApplication)
First thing I want to do is explicitly declare all variables.
Using code I got at the following address
stackoverflow.com/questions/19783180/get-list-of-all-properties-for-an-object
I used the "TypeLib Information" and the function TypeName() to determine each object type. I tried declaring as follows
Dim session as GuiSession
Dim MyApplication as GuiApplication
Dim Connection as ISapConnectionTarget
Dim SapGuiAuto as object
I'm getting the User-defined type not defined error.
After a bit of searching, I found the partial answer at this address.
scn.sap.com/thread/3254335
I feel manual adding the "C:\Program Files (x86)\SAP\FrontEnd\SAPgui\sapfewse.ocx" reference will break easily. If there's a better way to do this please let me know.
Ok now I can declare like this and it works.
Dim MyApplication As SAPFEWSELib.GuiApplication
Dim Connection As SAPFEWSELib.GuiConnection
Dim session As SAPFEWSELib.GuiSession
Dim SapGuiAuto As Object
I don't like the SapGuiAuto As Object as it doesn't really say what it is and I can't use CTRL+SPACE to view available properties and functions of this object (one of the VB features I can't live without now !)
All I know about this object is that it has a .GetScriptingEngine function (method ?).
While doing the research to write this question I came across this thread on the sap.com forums.
scn.sap.com/thread/3448120
Here it is mentioned that "GetScriptingEngine is a method of the class GuiApplication".
So I tried the following declarations and it seems to work.
Dim MyApplication As SAPFEWSELib.GuiApplication
Dim Connection As SAPFEWSELib.GuiConnection
Dim session As SAPFEWSELib.GuiSession
Dim SapGuiAuto As SAPFEWSELib.GuiApplication
Now if I type "session." the list of possible properties appear.
But there is a problem !
If I type the following line
Debug.Print session.FindById("wnd[0]").Text
It gives an error (while it used to work just fine !).
The error is "Object variable or With bock variable not set".
If I comment out the variable declarations, it works just fine !
Using the TLI function while session is undeclared I get the following members
DumpProperties session.FindById("wnd[0]")
output here -> pastebin.mozilla.org/8882551
but if I run the same command with session properly declared I get.. the same error
So after a bit more research, it turns out that the beginning of the script doesn't work the same now.
If Not IsObject(MyApplication) Then
Will not execute if MyApplication has been declared with Dim MyApplication As SAPFEWSELib.GuiApplication
So I tried executing the commands without the IFs.
Set MyApplication = SapGuiAuto.GetScriptingEngine
Set Connection = MyApplication.Children(0)
Set session = Connection.Children(0)
This fails with the "Object variable or With bock variable not set" error on Set MyApplication = SapGuiAuto.GetScriptingEngine
The solution to this issue was to create a new instance of SapGuiAuto like this.
Set SapGuiAuto = New SAPFEWSELib.GuiApplication
Now the above code executes, until it fails at Set Connection = MyApplication.Children(0)
The error : "The enumerator of the collection cannot find en element with the specified index"
A quick test with the following line reveals, the .Children collection is empty.
For Each chld In MyApplication.Children: Debug.Print "one exists": Next
This is the same error I would normally get if I am currently disconnected from SAP, but I am connected and commenting out the declaration block, fixes the issue.
This answer on stackoverflow is ominous
stackoverflow.com/questions/36751819/sap-gui-scripting-error-the-enumerator-of-the-collection-cannot-find-an-elemen
I'm not an administrator, it's 10 PM on a Friday and asking IT anything is a nightmare. Hopefully I don't have to resort to that.
I will try on another computer.
Just tried, I get the same thing. At this point I have to throw in the towel, I can't get this to work without some help or at least a good night's rest !
Thanks for any advice or comments
Some extra links I found very useful for the people on the same path as I am.
SAP GUI Scripting API PDF
Using the VBA debugger to discover SAP GUI properties and functions
scn.sap.com/docs/DOC-39696
SAP GUI Scripting API Documentation (I couldn't open this file but it's full of good stuff)
www.sdn.sap.com/irj/scn/go/portal/prtroot/docs/library/uuid/a034a16b-3bfe-2a10-e2bb-8bd880db0b3c
SAP GUI Scripting API : How to Automate User Interaction (unfortunately my system lacks the "Script development tools")
scn.sap.com/docs/DOC-4614
Also the BIBS function might be helpful to you, however it was not working on my system
scn.sap.com/docs/DOC-4612
When I use this I also get 0 children as if not connected to SAP:
Set sapCon = New SAPFEWSELib.GuiApplication
By using this instead it's actually working:
Set sapCon = GetObject("SAPGUI").GetScriptingEngine
As per this: https://answers.sap.com/questions/12487790/what-are-the-differences-in-vba-methods-to-connect.html?childToView=12494892
I just came accross this issue myself, and found a solution for the "enumerator" error. Also posted it in the referenced stackoverflow post you mentioned.
Change this:
Set Connection = Sap_Application.Children(0)
Into this:
Set Connection = Sap_Application.Children(1)
As I explained there, not sure why this happens, or what it means, I just messed with the numbers and it worked.
Hope it's not too late, or maybe it will help someone else.
Regards
how can i check if an instance of a workbook already exist? During my programm i would be able to close excel without the application crash...
When i'm using the instance in the programm i want to check if the instance exist when not, i open it again...
thanks
Dim neue_excelinstanz As excelapp.Application
Dim neue_workbook As excelapp.Workbook
Dim neue_worksheet As excelapp.Worksheet
neue_excelinstanz = CType(CreateObject("Excel.Application"), Microsoft.Office.Interop.Excel.Application)
neue_workbook = CType(neue_excelinstanz.Workbooks.Open("C:\Users\global.xlsx"), Microsoft.Office.Interop.Excel.Workbook)
neue_worksheet2 = CType(neue_workbook.Worksheets(2), Microsoft.Office.Interop.Excel.Worksheet)
Would it maybe just be an If block? Im not sure how to code in German, but:
If neue_workbook Is Nothing Then
neue_workbook = CType(neue_excelinstanz.Workbooks.Open("C:\Users\Nicolas Grichting\Desktop\Vmc_vapeur\global.xlsx"), Microsoft.Office.Interop.Excel.Workbook)
End If
I would maybe also use threading.sleep to give it time to load before having the program try it again. But this depends on how youre using this.
I have following code to run saved query and export data to excel report.
How should I change the code if this query is in a different database?
DoCmd.Requery Q_Check_Mismatches
DoCmd.RunSavedImportExport "Export-Q_Check_Mismatches"
I know we can link all relevant tables to current database and then run the query locally. But I need this
because of DB size issue.
Appreciate your response
Cheers
Shabar
Following code worked for me
Function QueryRun(strDBPath As String, strImportExport As String)
Dim objAccess As Access.Application
Set objAccess = CreateObject("Access.Application")
objAccess.OpenCurrentDatabase
strDBPath objAccess.DoCmd.RunSavedImportExport strImportExport
objAccess.CloseCurrentDatabase
objAccess.Quit
Set objAccess = Nothing
End Function
Cheers
Shabar
I'm following code I found on another site. Here's the basics of my code:
Dim SQL As String
Dim connString As String
connString = "ODBC;DSN=DB01;UID=;PWD=;Database=MyDatabase"
SQL = "Select * from SomeTable"
With Worksheets("Received").QueryTables.Add(Connection:=connString, Destination:=Worksheets("Received").Range("A5"), SQL:=SQL)
.Refresh
End With
End Sub
The problem with doing this is every single time they hit the button assigned to this it creates a new connection and doesn't ever seem to drop it. I open the spreadsheet after testing and there are many versions of the connection listed under Connections.
Connection
Connection1
Connection2
I can't seem to find a way to close or delete the connections either. If I add ".delete" after ".Refresh" I get a 1004 error. This operation cannot be done because the data is refreshing in the background.
Any ideas how to close or delete the connection?
You might ask yourself why you're creating a QueryTable every time in your code. There are reasons to do it, but it usually isn't necessary.
QueryTables are more typically design-time objects. That is, you create your QueryTable once (through code or the UI) and the you Refresh the QueryTable to get updated data.
If you need to change the underlying SQL statement, you have some options. You could set up Parameters that prompt for a value or get it from a cell. Another option for changing the SQL is changing it in code for the existing QueryTable.
Sheet1.QueryTables(1).CommandText = "Select * FROM ...."
Sheet1.QueryTables(1).Refresh
You can select different columns or even different tables by changing CommandText. If it's a different database, you'll need a new connection, but that's pretty rare.
I know that doesn't answer your question directly, but I think determining whether you really need to add the QueryTable each time is the first step.
For more on Parameters, see http://dailydoseofexcel.com/archives/2004/12/13/parameters-in-excel-external-data-queries/ It's for 2003, so there are few inconsistencies with later versions. The basics are the same, you just may need to learn about the ListObject object if you're using 2007 or later.
I had the same issue. The previous answer while a definite step in the right direction is a PITA.
It did however allow me to refine my search and the winner is...
http://msdn.microsoft.com/en-us/library/bb213491(v=office.12).aspx
i.e. for your existing QueryTable Object just do this:
.MaintainConnection = False
Works ever so swell. No more Access DB lock file after the data is refreshed.
You should declare the connection as a separate object then you can close it once the database query is complete.
I don't have the VBA IDE in front of me, so excuse me if there are any inaccuracies, but it should point you in the right direction.
E.g.
Dim SQL As String
Dim con As connection
Set con = New connection
con.ConnectionString = "ODBC;DSN=DB01;UID=;PWD=;Database=MyDatabase"
Worksheets("Received").QueryTables.Add(Connection:=con, Destination:=Worksheets("Received").Range("A5"), SQL:=SQL).Refresh
con.close
set con = nothing
I've found that by default new connections created this way are called "Connection". What I am using is this snippet of code to remove the connection but retain the listobject.
Application.DisplayAlerts = False
ActiveWorkbook.Connections("Connection").Delete
Application.DisplayAlerts = True
It can easily be modified to remove the latest added connection (or if you keep track of the connections by their index).
Application.DisplayAlerts = False
ActiveWorkbook.Connections(ActiveWorkbook.Connections.Count).Delete
Application.DisplayAlerts = True
Instead of adding another query table with the add method, you can simply update the CommandText Property of the connection. However you have to be aware that there is a bug when updating the CommandText property of an ODBC connection. If you temporarily switch to an OLEDB connection, update your CommandText property and then switch back to ODBC it does not create the new connection. Don't ask me why... this just works for me.
Create a new module and insert the following code:
Option Explicit
Sub UpdateWorkbookConnection(WorkbookConnectionObject As WorkbookConnection, Optional ByVal CommandText As String = "", Optional ByVal ConnectionString As String = "")
With WorkbookConnectionObject
If .Type = xlConnectionTypeODBC Then
If CommandText = "" Then CommandText = .ODBCConnection.CommandText
If ConnectionString = "" Then ConnectionString = .ODBCConnection.Connection
.ODBCConnection.Connection = Replace(.ODBCConnection.Connection, "ODBC;", "OLEDB;", 1, 1, vbTextCompare)
ElseIf .Type = xlConnectionTypeOLEDB Then
If CommandText = "" Then CommandText = .OLEDBConnection.CommandText
If ConnectionString = "" Then ConnectionString = .OLEDBConnection.Connection
Else
MsgBox "Invalid connection object sent to UpdateWorkbookConnection function!", vbCritical, "Update Error"
Exit Sub
End If
If StrComp(.OLEDBConnection.CommandText, CommandText, vbTextCompare) <> 0 Then
.OLEDBConnection.CommandText = CommandText
End If
If StrComp(.OLEDBConnection.Connection, ConnectionString, vbTextCompare) <> 0 Then
.OLEDBConnection.Connection = ConnectionString
End If
.Refresh
End With
End Sub
This UpdateWorkbookConnection subroutine only works on updating OLEDB or ODBC connections. The connection does not necessarily have to be linked to a pivot table. It also fixes another problem and allows you to update the connection even if there are multiple pivot tables based on the same connection.
To initiate the update just call the function with the connection object and command text parameters like this:
UpdateWorkbookConnection ActiveWorkbook.Connections("Connection"), "exec sp_MyAwesomeProcedure"
You can optionally update the connection string as well.
If you want to delete if right after refresh you should do the refresh not in the background (using first parameter -> Refresh False) so that you have proper sequence of actions
Try setting the QueryTable.MaintainConnection property to False...
"Set MaintainConnection to True if the connection to the specified data source is to be maintained after the refresh and until the workbook is closed. The default value is True! And there doesn't seem to be a UI check box for this (Read/write Boolean)"
Still relevant years later...battling the same issue and this is the most helpful thread out there. My situation is a variant of the above and I will add my solution when I find it.
I am using an Access database for my data source and establish a querytable on a new sheet. I then add two more new sheets and try to establish a querytable using the same connection on each of them, but to a different Access table. The first querytable works just fine and I use .QueryTables(1).Delete and setting the querytable object to Nothing to make it disconnected.
However, the next sheet fails on establishing a new querytable using the same connection, which was not closed. I suspect (and will add the solution below) that I need to drop the connection before deleting the querytable. Rasmus' code above looks like the likely solution.