Can a method in vba call another method - excel

I have written some code to connect to a database with excel.
When retrieving information from the database you need two things when using ADODB.
- Connection to the database
- record to retrieve the information.
Now I have used the copy past to change what needs to be changed.
This creates a lot of duplicate data for setting the connection whats is always the same
can something be done like this.
Sub StartQ1
Call Openconnection
Call DoStuffWithRecord
Call CloseConnection
End sub
or can something be done like this
Sub StartQ1
call Connection( call DoStuffWithRecord )
en sub
Thanks

Let me transpose your question: When you make a phone call you establish a connection, then you talk, and when you finish talking you close the connection. Now, is it possible to establish the connection and talk in one operation? Perhaps the first counter question to come up is why I should want that.
I think what you mean is to return the connection to the Main procedure from a function call like
Set MyConnection = OpenConnection()
' then use the connection to make your call
MyData = GetData(MyConnection)
' pass the data to the manipulating procedure
DoStuffWithRecord MyData
' and then close the connection
CloseConnection MyConnection
The subject of your question is how to pass data and objects as parameters to procedures and function. There is a lot of literature on this available on the web. Prepare to invest an hour of your time. This link may not be the first one you will need but it's a good, useful and reliable source of knowledge.

Related

Excel VBA Using MS Access DB Should I close connection?

I'm creating an Excel VBA program for people at my office. The way I intend it to work is each person will have their own "portal", an Excel document where they can interact with the DB with their own user settings. This way there won't be issues with multiple people trying to use an Excel file at the same time.
The thing I'm not sure about is the Access Database I'm setting up. It's a single DB file that everyone can access. Currently the plan is to create the connection this way:
Dim accessFileLoc As String: accessFileLoc = "C:\Users\gmloo\OneDrive\Desktop\Grab Project\GrabDB.accdb"
'create the connection object, and open the connection
Set accessCon = CreateObject("ADODB.connection")
'i HOPE setting the mode like this will allow multiple users to connect to the same
'db at the same time
accessCon.Mode = 16 + 3 'adModeShareDenyNone + adModeShareReadWrite
accessCon.Open "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & accessFileLoc
accessCon is a global Excel VBA variable that is currently designed to hold the connection as long as the Excel program is open. My question is, will this cause problems with other users all Querying the DB file at the same time? Should I be closing the connection for each user while it isnt needed, then re-establish it when they have to do a query? There's probably going to be up to 15 people using their Excel portal at any given time.
Thanks for your help.
You should be fine with multiple users connecting at the same time. However, due to memory and performance issues, I would recommend you close the connection after each query.

How many times to use 'Call doc.save(True, False) in a code?

Im coding an agent in Lotus Script. The code looks like this:
Sub Initialize
' * Some more code *
Set item = doc.ReplaceItemValue("form_Initialize_Status01", "Command 1 successful run.")
Set item = doc.ReplaceItemValue("form_Initialize_Status02", "Command 2 successful run.")
' * Some more code *
Call Sub_Action()
' * Some more code *
Set item = doc.ReplaceItemValue("form_Initialize_Status03", "Command 3 successful run.")
End Sub
Sub Sub_Action()
' * Some more code *
Set item = doc.ReplaceItemValue("form_Sub_Action_Status01", "Command 1 successful run.")
' * Some more code *
Set item = doc.ReplaceItemValue("form_Sub_Action_Status02", "Command 2 successful run.")
End Sub
Question:
What is the recommanded way to put the following line to save the document?:
Call doc.save(True, False)
After each Set item = doc.ReplaceItemValue or only once in the end of the Sub?
TL;DR: Only save ONCE at the end.
There are several things to consider here:
First of all: ReplaceItemValue- operations are purely modifications to the document in memory. They do not trigger any database operations (aka disk writes).
The "Save"- Operation on the other hand DOES trigger database operations.
Even without considering the performance impact this should be reason enough to save as economical as possible.
But now lets additionally consider the side- effects of a solution that saves after every change of an item:
Your code might transfer a document from one state to the other. To completely achieve this transfer, ususally ALL items need to be changed to their new state in the document.
Code is NEVER 100% bug free. And even if it is: The code can fail for whatever reason in the middle of execution.
Whatever the reason is for your code stopping after the first 5 items: If you save every single change, then your document will be in an inconsistent state and you need to write code to rollback the changes or start where the code left and complete the changes.
Better do ALL your transofrmations and then save at the very end, when everything is done and consistent.
One exception for this is writing log- documents where you add the progress adding lines to the log. If you want to observe the progress from another place, then saving after every log- entry- line would be the right thing to do. But there are not much other scenarios where this would be true.

AX X++ return reader form method and close connection to database

Dynamics AX :
I am fetching data from an external server using OLEDB Connection in X++ class in order to insert it into the application/AX database
.
However, I have created a class that contains a method getreader this method will create a connection to an external database and then return an System.data.oled.oledbdatareader as output and this output will be processed by another class to do the necessary computation.
Furthermore, the above method will be called by many classes not only one which make me worried about the number of connection opened with the database especially I didn't manage to close it after returning the reader.
I googled how to close connection while returning the reader and I have concluded that I can close the connection as per the below
connection.ExecuteReader(CommandBehavior.CloseConnection)
The above code is written in c# and I couldn't do the same in X++.
How could I solve the problem in dynamics AX and what is the impact of keeping the connection open?
You can wite as
connection.ExecuteReader(System.Data.CommandBehavior::CloseConnection);
I'm not sure if this works as reader could not move to the next row if the connection would be closed.

QueryTable.Refresh causes incomplete OLE action; how to complete?

I'm trying to auotmate this report and have written VBA to perform various tasks, then I call each of them sequentially in a "RunAll" sub. I have data from an Access query to a tab in my workbook for a pivot table.
I've discovered that when I run this:
Sub QueryTableRefresh()
ActiveWorkbook.Sheets("data").Activate
Range("A2").Activate
Selection.ListObject.QueryTable.Refresh BackgroundQuery:=False
End Sub
it creates an incompelte OLE action with Access, which causes a Read Only instance of Access to open when I run the below ("TableRefresh" is a function with delete and append queries):
Public Sub RefreshAccessTables()
Dim acApp As Object
Dim db As Object
Set acApp = CreateObject("Access.Application")
acApp.OpenCurrentDatabase ("P:\Reports\Daily Origination Volume\Daily Origination Volume.accdb")
Set db = acApp
acApp.Run "TableRefresh"
acApp.Quit
Set acApp = Nothing
End Sub
The read only instance prevents the writing actions of the delete and append queries. This is not the sequence in which these two run within my RunAll, but the workflow would require that the RunAll would be run again if any updates are made, which then causes the conflict.
I've run the Access function from Excel multiple times back to back and have no problems, until I run the querytable refresh. Refreshall causes the same problem.
How do I update only my query table in Excel, without leaving this OLE action incomplete?
I discovered that the problem may be alleviated by choosing another method to import the data, that being MS Query. Rather than choosing the "From Access" option for importing data, choose "From Other Sources" then "From Microsoft Query."
After using this import method, I refreshed it multiple times back to back. Immediately following the refreshing, I was able to open the source database in read/write mode.

Insert/Update SQL table from observablelist

Ok, so I'm working with an ObservableList, which is working fine, but now I need to use the observable list to insert rows into and update rows in an SQL database table. I've found little info on working between JavaFX and SQL databases ... all the examples of data tables have the data created in the java code. I had hope when I saw "update SQL database" in this post:
Update sql database from FoxPro data on Glassfish server
but it was not applicable to my situation.
So the question is, how do I start the code to read from the ObservableList so I can run my SQL Insert statement? If you could point me to an example code where an ObservableList is used and an SQL table is created/added to/updated I would greatly appreciate it.
Thanks!
UPDATE TO QUESTION:
I can't really post relevant code here because the relevant parts are what I don't have. However, I'm thinking what I need to do is something like this:
mylist.moveToFirst();
while (mylist.next()) {
make connection // think I got it
INSERT INTO mytable (name, address, phone) VALUES (observablename, observableaddress, observablephone // think I got this as well
Obviously I'm applying my knowledge of other areas to ObservableList, but I am doing it to demonstrate what I don't know how to do with my ObservableList (mylist).
Again, thanks for any help.
Tying up loose ends today, and this question has not really been answered. I reposted a newer question with more specifics once I learned more about the situation, and that question also went unanswered, but I did figure it out, and posted an answer here: Understanding my ObservableList.
However, to be neat and tidy, let me post here some code to help me remember, as well as help anyone else who looks at this question and says, "YES, BUT WHAT IS THE SOLUTION?!?!?"
Generically, it looks something like this:
I like to open my connection and prepare my statement(s) first.
Use the iterator to get the variables from the list
within the iterator, add the variables to the prepared statement and execute.
I read somewhere about batch execution of statements, but with as few updates as I'm doing with each list, that seemed too complicated, so I just do each update individually within the iterator.
Specifically, here is some code:
Connection con;
con = [your connection string]; // I actually keep my connection string in its own class
// and just call it (OpenDB.connect()). This way I can swap out the class OpenDB
// for whatever database I'm using (MySQL, MS Access, etc.) and I don't have to
// change a bunch of connection strings in other classes.
PreparedStatement pst;
String insertString = "INSERT INTO People (Name, Address, Phone) VALUES (?, ?, ?)";
pst = con.prepareStatement(insertString);
for(Person p : mylist) { // read as: for each Person [a data model defined in a class
// named Person] which in this set of statements we shall call 'p' within the list
// previously defined and named 'mylist' ... or "For each Person 'p' in 'mylist'"
String name = p.name.get(); // get the name which corresponds to the Person in this object of 'mylist'
String address = p.address.get(); // ditto, address
Integer phone = p.phone.get(); // ditto, phone. Did as integer here to show how to add to pst below
pst.setString(1, name); // replace question mark 1 with value of 'name'
pst.setString(2, address); // ditto, 2 and 'address'
pst.setInt(3, phone); // ditto, 3 and 'phone'
pst.executeUpdate();
And that's how I did it. Not sure if it's the 'proper' way to do it, but it works. Any input is welcomed, as I'm still learning.
In JavaFX you usually get to be the person to create the example :)
ObservableList supports listeners, these receive events which tell you what has been added or updated by default. There is a good example in the javadocs here.
To get update events you need to provide an 'extractor' to the method creating the list here. This should take an instance of the object in the list and provide an array of the properties you want to listen to.
Try this:
SQLEXEC(lnConn, "Update INVENTORY SET brand = ?_brand, model = ?_model, code =?_code, timestamp =?_datetime where recno=?_id ")

Resources