mySQL-query from Microsoft Access VBA fails if not interactive? - mysql

I'm fighting with a VBA non-interactive problem that really bugs me: I have a pass-through query to a mysql database, which works well if double-clicked by the user. But it fails if called from VBA automation session (called from excel) if no interaction was done first. Most strange: it works from VBA after clicking it on the GUI for a while (odbc mysql connection timeout possibly).
The passthrough-query has it's password in the DSN and in the connection string (to sort out problems with the store). The behavior is the same with a linked table.
Problematic VBA code called looks like this:
CurrentProject.Connection.Execute "INSERT INTO [SomeLocalTable] (id) SELECT id FROM [somePassThroughOrLinkedMySQLTable]"
The error is a generic odbc connection failure 80004005.
While this type of query works all the time:
Dim cnn As New ADODB.Connection
cnn.Open ("Driver=MySQL ODBC 5.2w Driver;SERVER=myserver;UID=user;DATABASE={db};PORT=3306;DFLT_BIGINT_BIND_STR=1;PWD=secret")
Can I "initialize" the passthrough query like the UI does to make it work? Or can I use the second type of query to insert into a local MS Access table?
Environment: Win8-64bit, Office2013, mysql-odbc-5.2w

I think the problem is happening because you are referring to the Access database as an external ADODB data source, instead I would use an instance of Access in order to run the query via DAO. The sample sub below creates an invisible instance of Access and executes the query, and then quits once finished. I've used late binding in this example with DAO version 3.6 so you may need to amend that bit slightly or use early binding:
Sub ExecPassThru()
Dim acApp As Object
Dim acDb As Object
Set acApp = CreateObject("Access.Application")
Set acDb = CreateObject("DAO.DBEngine.36") 'May need slight alteration
acApp.OpenCurrentDatabase ("C:\db1.mdb") 'Amend as required
Set acDb = acApp.CurrentDb
acDb.Execute "INSERT INTO [SomeLocalTable] (id) SELECT id FROM [somePassThroughOrLinkedMySQLTable]"
acDb.Close
acApp.Quit 2
End Sub
This was coded using Excel 2003 but should be easy enough to translate to later versions of office.

Related

How to write into a currently open MS Access 2010 Database from within another MS Access 2010 Database via VBA

I am able to connect to a remote .accdb file to write content into a table as long as the target database is not currently open, but I am forced to write into that database even while it is open. Doing copy and paste manually from database1.tableA to database2.tableA while both are open works fine. But why does VBA not get the job done? Here is what I've tried so far:
Way 1:
...
Dim dbTarget As Database
Set dbTarget = DBEngine.Workspaces(0).OpenDatabase("X:\path\to\file.accdb")
...
Error (translated from German):
... failed with error (3029): No valid account name or no valid password.
Way 2:
...
Dim wrkDev As Workspace
Dim dbTarget As Database
Set wrkDev = CreateWorkspace("", "Admin", "", dbUseJet) ' adopted from microsoft docs
Set dbTarget = wrkDev.OpenDatabase("X:\path\to\file.accdb", True)
...
Error (translated from German):
... failed with error (3029): No valid account name or no valid password.
Why is that and how to fix?
There are several ways to open databases and database connections in Access. You've shared several, but can attempt others too. I'm assuming you're using DAO recordsets to do the inserting.
Open a database in a separate Access application, and create a reference to the database object
Dim A As New Access.Application
A.OpenCurrentDatabase "X:\path\to\file.accdb"
Dim db As Database
Set db = A.CurrentDb()
Open a recordset on a remote database using the SQL IN statement in the FROM clause
Dim rs As Recordset
Set rs = CurrentDb.OpenRecordset ("SELECT * FROM MyTable IN ""X:\path\to\file.accdb""")

What Could Be Causing Crystal Report in Visual Studio 2010 To Display Gibberish?

Good morning,
After watching numerous online tutorials and reading the Documentation, I decided to get hands on with the Crystal Reports for Visual Studio runtime. It is my understanding that the SAP Crystal Reports runtime doesn't natively support connections to a MySQL DB so I believe I've done everything correctly to pull the DB records into a Dataset object. I can see the records in the Dataset and they match what's in the Database. Unfortunately, when I run a preview of the report everything is "gibberish" except for the Date fields.
I'm stumped and don't know what to do now, any assistance would be greatly appreciated. Screenshots below show the records from the Dataset as well as the Report preview.
By the way, the Collation on the server and table are both set to "Latin1 - Default Collation" - not sure if that makes any difference.
IMAGE #1: VIEW OF DATASET RECORDS
Click here for a larger image: https://dl.dropbox.com/u/55174425/Dataset%20Records.jpg
IMAGE #2: DESIGN VIEW OF REPORT
Click here for a larger image: https://dl.dropbox.com/u/55174425/Design%20View%20of%20Report.jpg
IMAGE #3: PREVIEW OF REPORT
Click here for a larger image: https://dl.dropbox.com/u/55174425/Preview%20of%20Report.jpg
Hello SO,
I managed to answer my own question and decided to share my answer in case somebody out there runs into this same problem.
Well, it's not so much a problem as it is the actual way the Crystal Reports for Visual Studio runtime is supposed to work (at least when it comes to MySQL). What I didn't realize was that, because the CR runtime for VS didn't support a native connection to a MySQL database, it was necessary to use Visual Studio to create a Server Connection using the .Net Connector (which is made available when you install the Connector).
Once the server connection was made, I was then able to create a DataSet and populate it with the records from the DB. Unfortunately, what I didn't realize was that this dataset simply allows for the selection of the fields/columns necessary for the designing of the report (.rpt file). Now, here's where my "gibberish" problem was. In fact, I discovered that the CR runtime purposefully uses random text/characters when you're designing the report and if you preview the report you will see this. Also, if you debug the application you will get a blank report with only the column headers.
The solution to this is to programatically query the DB, create and fill a DataTable and assign it to a new instance of the report you just created as its datasource. And viola, the report now shows the information I was looking for. So, here's the code I ended up using at run-time in order to get my report to display the data I was looking for:
Private Sub Form2_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Try
'Define the MySQL Connection String.
Dim myConnectionString As String = "Server=server_address;Port=3306;Uid=user_id;Password=password;Database=schema_name;"
'Create a new MySqlConnection object and assign the Connection String to it.
Dim dbConn As New MySqlConnection(myConnectionString)
'Define your Query.
Dim dbQuery As String = "SELECT * FROM users"
'Create a new MySqlDataAdapter object and assign the Query and Connection String objects to it.
Dim dbAdapter As New MySqlDataAdapter(dbQuery, dbConn)
'Create a new DataTable object and fill it with the contents of the MySqlDataAdapter object.
Dim dbTable As New DataTable
dbAdapter.Fill(dbTable)
'Create a new instance of the report you previously designed and set its DataSource to the DataTable.
Dim report As New rptUserList
report.SetDataSource(dbTable)
'Set the ReportSource of the CrystalReportViewer control to your report.
CrystalReportViewer1.ReportSource = report
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub

How do I establish a connection to MySQL via VB & display simple query results on a form?

I have a project in Visual Studio 2008 and there is a working data connection to a MySQL database. In other words, I can query the db directly from Visual Studio and it will display the results.
I've tried a couple of approaches that I found online for writing a connection string and accessing the db, but no luck yet.
All I'm trying to do is code a button to query the db and then reset the text property of a label/textbox to display the results based upon another label/textbox value.
The pseudo-code I am imagining is something like this:
Private Sub query_submit_button_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles query_submit_button.Click
result_textbox.Text = SELECT field FROM table WHERE otherfield = key_textbox.Text
End Sub
I didn't see any related questions posted on SO - forgive me if I missed one that already exists and this is a dupe.
What is the correct way to accomplish this?
EDIT
Using MySQL 5.1
You can download the ODBC Provider and then reference, import, and use it to query the database through a ODBCCommand instance.
'Put this at the very top of your .VB file...
Imports System.Data.ODBC
'Put this in some method in your code when you are ready to query the DB...
Using connection As New OdbcConnection(connectionString)
Dim command As New OdbcCommand(strSqlQuery, connection)
connection.Open()
result_textbox.Text = command.ExecuteScalar.ToString
End Using
i used DaMartyr's answer to get 99% there, but needed to add this declaration:
Dim connectionString As String = "driver={MySQL ODBC 5.1 Driver};server=SERVER;uid=USERID;pwd=PASSWORD;database=DATABASE"
just replace the SERVER, USERID, PASSWORD, & DATABASE with your personal settings

Is there a way to execute VBA code when specific tables and fields in a Microsoft Access database are updated?

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

Connect SQL Server Compact 3.5 Database to MS Access 2003 using ADO?

Is it possible to write connect and open a SQL Compact 3.5 database from within MS Access 2003? I want to be able to use MS Access 2003 to manipulate data in a SQL Compact 3.5 database. If it is possible, then what statements would be used to open the database?
This is just an idea and I can't confirm that it will work, but given that SQL Compact lacks an ODBC driver and you can't have linked tables, perhaps you can use an OLEDB connect string for SQL Compact as the Source Connect String of a saved QueryDef in Access. If you can get that to work you may be able to create a saved QueryDef for each table, and then utilize them as though the queries were linked tables.
I can't test it on my machine because the only OLEDB provider I have installed is Jet, and Access doesn't seem to like that.
But it might be worth a try. Possibly it's not going to work, as I can't find anywhere that anyone has done this in Access. But I don't really see why it shouldn't work.
Again, I could simply be wrong, though.
Though I did not try it specifically with SQL Compact, connecting to the server should be standard:
Check that the ADODB file (msado21.tlb) is correctly refernced in your available tools
Write down your connection string somewhere like this one:
MyConnectionString = "Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=YourDatabaseName;Data Source=YourSQLServerInstanceName"
This string is written for an 'integrated security' context. In cas you want to change it for an SQL security context, please check here to update the string. Ideally, this string should be declared as a public variable in your code.
Once this is done, you can open an ADODB recordset and begin to manipulate it:
public sub connectionTest
Dim activeConnection as ADODB.connection, _
activeRecordset as ADODB.recordset
Set activeConnection = New ADODB.connection
activeConnection.connectionString = myCOnnectionString
activeConnection.open
set activeRecordset = New ADODB.recordset
'this will open a read-only recordset'
activeRecordset.open _
"SELECT * FROM myTableName", _
activeConnection, _
adOpenStatic, _
adLockReadOnly
if activeRecordset.EOF and activeRecordset.BOF then
debug.print "No records in this table"
else
activeRecordset.moveFirst
do while not activeRecordset.EOF
debug.print activerecordset.fields("myFieldName").value
activeRecordset.moveNext
loop
endif
activeRecordset.close
set activeRecordset = nothing
activeConnection.close
set activeConnection = nothing
end sub