My current team of 20 people uses an access database front end on their desktop. The backend of the access database is on a network drive. I have been asked to create an access database front end with MYSQL as the back end.
I have installed the MySQL workbench and the ODBC connector on my computer. I have created the schema and tables and I have connected the front end of the database connected to the MYSQL table I created in workbench. My question is
How do I deploy this for the team to use. I believe I can move the front end of the access dB to the network drive and the team can copy it to their desktop. But what do I do about the backend?
Does the team need to have the ODBC connector installed on their computers?
Should I move the MySQL workbench to the network drive?
PS: I am a new developer and just learning about databases and I am only familiar with the access database please go easy on me.
Thanks.
SO is for questions about coding, so this is OT. However:
One method is described in my article:
Deploy and update a Microsoft Access application with one click.
The old backend, you can archive. It will not be used anymore.
Yes.
Probably not. It is only for you, should you need to modify the
MySQL database.
Well, first up, you STILL need and want to deploy the application part called the front end (FE) to each workstation.
So, after you migrate the data to MySQL, then of course you will use the access linked table manager, and now link the tables to MySQL. How this works is really much the same as you have now. The only difference is that you linked tables now point to the database server (MySQL). From the application point of view, it should work as before.
Like all applications, be it Outlook, Excel, accounting packages? You STILL deploy the application part to each workstation. So just because YOU are now developing and writing software with Access does not mean out of the blue that you now for some strange reason STOP deploying the FE part to each workstation. In fact, you should be deploying a compiled version of your application (a accDE).
A few more tips:
WHEN you link the FE, MAKE SURE you use a FILE dsn. The reason for this is Access converts the links to DSN-less for you. What this means is that once you link the tables, then you are free to deploy the FE to each workstation and it will retain the linked table information WITHOUT you having to setup a DSN connection on each workstation. You will also have to of course deploy the MySQL ODBC driver to each workstation as that is not part of Access nor it is part of your application.
So just because you are now developing software does not suggest nor get you off the hook of deploying that application to each workstation. So, your setup you have now with a FE on each workstation does NOT change one bit.
For the most part, after you migrate the data to MySQL, then likely setup your relationships (say with MySQL workbench) there are several other things you need to keep in mind.
All tables now need a primary key. You likely have this, but Access with a access back end did and could work on tables without a PK. However, for SQL server/MySQL etc., then all tables need that PK.
Next up:
If you have any true/false columns, you MUST set a default up for that column. If such true/false columns have a default value or allow nulls, this will confuse access - so ensure that true/false columns can't have nulls and have default (useally 0) setup on the server side.
Add a "rowversion" column. This is not to be confused with a datetime column. In SQL server this rowversion column is of timestamp data type (a poor name, since the column has zero to do with time - it is simply a column that "versions" the row. This will also eliminate many errors. I don't know what this type of column is called in MySQL, but all tables should have this column (there is zero need to see/use/look at this column on your forms - but it should be part of the table.
All of your forms, reports and code should work as before. For VBA recordset code, you need this:
dim rst DAO.Recordset
dim strSQL as string
strSQL = "SELECT * from tblHotels"
set rst = currentdb.OpenRecordSet(strSQL).
You likely in the past had lots of code as per above.
You now need:
Set rst = CurrentDb.OpenRecordset(strSQL, dbOpenDynaset, dbSeeChanges)
You can generaly do a search and replace (find each .OpenRecordSet, and add the dbOpen and dbSee to each line of code you find. (I put the dbOpenDynaset, dbSeeChanges in my paste buffer. And then do a system wide search. It takes a few minutes at most to find all .openRecordSets
At this point, 99% of your code, forms and everything should work.
The ONE got ya?
In access be it on a form or in VBA recordSet code? When you create a new row, or start typing on/in a form? Access with access back end would generate the PK at that point. There was/is no need to save the record to get the PK value. This need is rare, and in a large application I only had about 2 or 3 places where this occured.
So, if you have code like this:
dim rstRecords as RecordSet
dim lngPK as Long ' get PK value of new record
Set rstRecords = CurrentDb.OpenRecordset("tblHotels")
rstRecords.AddNew
' code here sets/ add data/ set values
rstRecords!HotelName = "Mount top Hotel"
rstRecords!City = "Jasper"
' get PK of this new record
lngPK = rstRecods!ID ' get PK
rstRecords.Update
So, in above code, I am grabbing the PK value. But with server systems, you can NOT get the PK value until AFTER the record been saved. So, you have to change above to
rstRecords.Update
rstRecords.Bookmark = rstRecords.LastModified
' get PK of this new record
lngPK = rstRecods!ID ' get PK
Note how we grab/get the PK AFTER we save.
The bookmark above simply re-sets the record pointer to the new record. This is a "quirk" of DAO, and WHEN adding new reocrds, a .Update command moves the record pointer, and thus you move it back with the above .LastModified. You ONLY need the .LastMOdifed trick for NEW reocords. For existing, you already have the PK - so it don't matter.
This type of code is quite rare, but sometimes in a form (and not VBA reocdset code), some form code we might use/need/get/grab the PK value. In a form, you can do this:
if me.dirty = true then me.dirty = false ' save reocod
lngPK = me.ID ' get PK
So, once again, in the above form code, I make sure the record is saved first, and THEN I grab the PK value as above. Of course this is ONLY a issue for NEW records. (and you don't have to use the bookmark trick - that's only for recrodsets - not bound forms.
So, just keep in mind in the few cases when you need the PK value of a NEW record, you have to do this AFTER you saved the recordset (update) or in the case of a form, after you forced a form record save. This requirement is only for new records and ALSO only when your code needs to get/grab the new PK value.
Other then the above two issues? All the rest of your existing code and forms should work as before.
Related
I have an Access Database connected(linked table) to an Oracle database.
I wrote some Select queries. Everytime I run it, I get an "Oracle ODBC Driver Connect" input box.
Is there way to write a vba macro to enter username and password (auto fill) and Enter Ok.
Trying to set up an auto run for macros in this Access db.
Any help is appreciated.
As pointed out, when you link the tables, you are given an option to save the password in those table links. If you missed this step, then you will get that ODBC prompt.
THIS HAS ZERO to do with you writing select queries. The simple matter is try clicking on one of the linked tables you use in such quires. Either you get an ODBC prompt or you do not.
If you do, then of course you going to get such a prompt when you write a query. YOU WANT to FIRST get the table links working without an ODBC prompt and THEN write those queries based on the linked tables.
So get the linked tables working first. Forget about and don’t’ worry about your queries you are writing. Until such time that a simple click on (opening) a linked table works and does not throw out the ODBC prompt, then you are looking at the WRONG problem.
Once you get your linked tables working without a prompt, then your queries will also work without a prompt.
So you have two choices to fix this problem.
Simple re-link your tables, and ensure that you select [x] check box during re-link to save the password.
The prompt you missed and want to select is this one:
Now if your tables are already linked and you run the linked table manger, you WILL NOT get this prompt anymore. So you have to delete the table links, and re-create.
Of course deleting the table links can often result in the linked table names being changed, and that can be a pain, especially if you have a LOT of linked tables. Only you can make this judgement call as to what is less work. If you have just a few tables, then just delete them, and use the external data -> then in the import and link secton, choose ODBC and you can add the tables, but REMEMBER to select (check) the above save password box as per above that you missed.
Now, most people over time wind up with some table re-link code VBA. So if you have suc re-link code already working and handy, then simply re-run that code with the user/password included in the connection string you use in that code. Of course if you don't have such code, then the above linked table manager in Access is a code free solution and is obviously your best choice and course of action.
So in place of above, you can find some table re-link code that will force (save) the user/id in the table links for you.
However, if you don’t want to delete + re-create all those tables, and you don’t have already setup some re-link code, there is also another (3rd) choice.
In your application start-up code simple execute a one-time logon. If you do this, then the ODBC prompt will not appear when you use the linked tables and hence also not appear when you attempt to run/build/use a query based on those linked tables.
The code to execute a one-time logon will look like this:
Function TestLogin(strCon As String) As Boolean
On Error GoTo TestError
Dim dbs As DAO.Database
Dim qdf As DAO.QueryDef
Set dbs = CurrentDb()
Set qdf = dbs.CreateQueryDef("")
qdf.connect = strCon
qdf.ReturnsRecords = False
'Any VALID SQL statement that runs on server will work below.
' this does assume user has enough rights to query built in
' system tables
qdf.sql = "SELECT 1 "
qdf.Execute
TestLogin = True
Exit Function
TestError:
TestLogin = False
Exit Function
End Function
Above code run ONE time on start-up of your application will thus eliminate the ODBC prompt(s) when you click on a linked table. And of course once that issue of linked tables is resolved, then of course creating or clicking on your query or running those quires will now ALSO work without the prompts.
You can NOT auto fill that prompt, you have to take CORRECT steps in the first place to PREVENT that prompt from appearing. So to answer your question?
No, you can't write code to enter the requested prompt, but if you link your tables with the password saved, or execute the above logon code, the prompt will NOT appear in the first place.
I have an Access Database which I populate using a pass through query.
I get specific data from an SQL database and dumps it on Access.
This Access DB is updated weekly but I cannot simply append new data from the previous week because all other past weeks also updates.
What I did is truncate the Access DB and then load everything again.
When I do that, I need to Compact and Repair the DB so that the size doesn't bloat.
My question is, is it ok to do that? Currently I am using the logic posted in this answer.
I have not encountered any problems yet but I just want to make sure and get our access guru's thought about it. Also I'm planning on doing a scheduled run on our server to do the task.
Just need to make sure that it will not get corrupted easily (what is the chance of corrupting the file in the first place?).
If you'll ask, why do I need to do this? Users of data have no access on SQL server.So I have to pull data for them so they can just connect to Access DB instead.
Just in case you need the code:
Dim sqlDelete As String
Dim sqlAppend As String
sqlDelete = "DELETE * FROM dbo_Table;"
sqlAppend = "INSERT INTO dbo_Table (Col1,Col2) SELECT Col1,Col2 FROM passThrough;"
With DoCmd
.SetWarnings False
.RunSQL sqlDelete
.RunSQL sqlAppend
.SetWarnings True
End With
Application.SetOption "Auto Compact", True
If you need to truncate the data and load again I would recommend to move all tables, which should be truncated and all temporary tables to separate database.
After separating it will be possible to replace this database with unnecessary data by empty database file when the application starts. Just save a copy of empty database and copy this file over existing database with old data. This should be done before opening any form/recordset based on tables from temp database. It will work faster than C&R each time and more reliable, because sometimes C&R may damage the file.
Template database file also can be stored in main database in Memo field
I will refer this forum post: http://www.utteraccess.com/forum/index.php?showtopic=1561733
I am converting a Large MS Access 2010 application to act as a front end to MySQL 5.5 database, via the v5.1 ODBC Connector, and I am experiencing a strange problem when inserting new records with bound data forms.
In a data-entry form, if the default value of a date field is set in the properties of the control as a constant (such as #04-01-2014#) the new record is created in MySQL successfully, and after saving, all fields are visible in their associated bound fields. But if the default value is defined in the Access control as a function (example: =Date()) then although the MySQL row is created successfully, ODBC fails to find the new row and Access displays all values as #DELETED. Refresh and/or requery commands are not helpful. This is nothing to do with the well known issue of -- must have a primary key and a datestamp in MySQL. All of these safeguards are in place, and as stated, it does work without FE defaults.
No defaults are being set in the MySQL backend, and it makes no difference whether or not Nulls are allowed. Data type used in the backend is DateTime. If I do set defaults in the BE and none in the FE, everything is fine. But that way, the user DOES NOT SEE THE DEFAULTS in the data entry form... an unacceptable situation.
I have also tested both ODBC v5.2, and MySQL 5.6 with exactly the same results.
A solution that seems to work (so far) is to set all defaults in code, in the form.beforeUpdate event. Something like this:
form_beforeUpdate()
if me.newrecord then
field1.value = date()
field2.value = fOtherDate()
'etc
end if
'other code
exit sub
I could insert all new records with unbound forms and passthrough queries. But with 75,000 lines of code, that is a very big job
My question is - why do I need these "workarounds"? Isn't the whole purpose of ODBC to allow fairly normal operation? What is it about simple functions that "breaks it"? What other "ordinary" Access methods will break it? If I don't understand why it didn't work I can't be sure it is properly fixed.
Has anyone else had any experience with this SPECIFIC issue? I could not find any reference to it elsewhere. Thank you for your time.
I'm looking for a way to implement SCM over multiple Access 07 databases. We just need source control for the forms/code.
Essentially we have 100+ databases that are structured the same, use the same code/modules, but each contains data for just one client. When we make a code change we currently have to manually go through each file to make the change.
Has anyone implemented source control for something similar(God help you if so) or have any ideas?
PS - I realize there is lots of DailyWTFery in here, this is a legacy product I've been assigned to do some emergency maintenance on before we rewrite to .NET/MSSQL, but I think there's enough work to warrant putting this in place if it's possible.
You can find out more how to do SCM in this question; it does involve exporting and importing the code and forms using some undocumented (or poorly documented) commands. I also recall issues with checksums or version numbers happening when you used that method.
However, you could solve a lot of this problem by separating the the data and the application sides of the DB into separate files and then adding table links to the data DB from the application DB. Then you would have just one Application DB, and oodles of Client data DBs.
Switching to a different client is as simple as re-linking to the other DB.
You can do that manually or code it with a structure something like this:
Dim myTable As TableDef
Dim db As Database
dim strDBPath as string
strDBPath = ";DATABASE=C:\workbench\MyNewDB.mdb"
Set db = CurrentDb
db.TableDefs.Refresh
For Each myTable In db.TableDefs
If Len(myTable.Connect) > 0 Then
myTable.Connect = strDBPath
myTable.RefreshLink
End If
Next
'' Note: This whips through every table in your database and re-links it to the new
'' DB. ODBC links will have a different value for strDBPath - I'll leave that as
'' and exercise for the reader
I am looking for a way to manage syncronization between an Access mdb file for an application, and a MySQL schema containing a copy of the same tables. This arose from the fact that the application doesn't support MySQL as a backend, but I am looking for a way to utilize MySQL for other in-office applications using the data the first application generates.
Some givens:
1> We cannot abandon the first application, and it's only compatible with Microsoft SQL Server as a backend server to house data.
2> We are not against using Microsoft SQL server, but the licensing cost is a big concern - as well as rewritting some other Access applications written to use linked tables and seperate mdb files.
3> The database server should be "PHP friendly" for a future expansion project for an internal corporate intraweb.
4> No data needs to be, nor should be allowed to be, accessed from outside the corporate network.
I hope I am not being too obscure, but I don't want to break confidences either - so I am trying to walk a pretty tight rope. If anyone can help, I'd greatly appreciate it.
Synchronizing two databases is very, very complicated if both databases need to be updatable. If one is a slave of the other, it's not nearly as difficult. I have more than once programmed just this kind of synchronization using Access, once with an MDB on a web server that had to be synched with a local data MDB (to incorporate data edited on the website; no edits went back to the website, so one-way synch, but still the need to merge edits on the non-web side), as well as once programming a synch between MySQL on a website and Access in a master (MySQL) / slave (Access) relationship.
On the website, you program a dump of data for each table to a text file. It's helpful to have timestamp fields in the MySQL tables so that you know when records were created and updated. This allows you to select which records to dump since the last data dump (which makes the synchronization of data on the Access side much simpler).
The way I programmed it was to then import the text files into staging tables that were indexed appropriately and linked to the front-end Access app. Once the data dumps are imported into the staging tables, you then have three tasks:
find the new records and append them to the Access data store. This is easily done with an outer join.
deal with the deletions. I'll discuss this later, as it's, well, complicated.
deal with updated records. For this, I wrote DAO code that would write column-by-column SQL statements.
Something like this:
UPDATE LocalTable
SET LocalTable.Field1 = DownloadTable.Field2, LocalTable.Updated = DownloadTable.Updated
WHERE LocalTable.Field1 <> DownloadTable.Field2
Now, obviously, the WHERE clause has to be a bit more complicated than that (you have to deal with NULLs, and you have to use criteria formatted appropriately for the data types, i.e., with "" and ## for text and dates, respectively, and no delimiters for numeric data), but writing the code to do that is pretty easy.
Skeleton code looks something like this:
Dim db As DAO.Database
Dim rsFields As DAO.Recordset
Dim fld As DAO.Field
Dim strSQL As String
Set rsFields = db.OpenRecordset("SELECT TOP 1 Field1, Field2, Field3 FROM LocalTable;")
For Each fld in rsFields
[write your SQL statement and execute it]
Next fld
Set fld = Nothing
rsFields.Close
Set rsFields = Nothing
Set db = Nothing
Now, as I said, the complicated part is writing the WHERE clause for each SQL statement, but that's pretty easy to figure out. Also, note that in your rsFields recordset (which is used only to walk through the fields you want to update) you want to include only the fields that are updatable, so you'd leave out the CREATED field and the PK field (and any other fields that you don't want to update).
Now, for the DELETES.
You might think it's a good idea to simply delete any record in the local table that's not in the remote table. That works fine if it really is a slave database, but so often what is originally a slave ends up getting its own edits. So, in that case, you need to not delete records from the master MySQL database, and instead have a DELETE flag that marks records deleted. You could have different varieties of logic that could clean the deleted records out of the master database (e.g., if you're using date stamps in the records, you could delete all records flagged DELETED with LastUpdated timestamp that is <= the last time you dumped the data; alternatively, you could have the Access app send a text file up to the server with a list of the records that have been successfully deleted from the Access data store). If there are edits in the Access data store, then you'll need some logic for dealing with an edit there on a record that was deleted from the MySQL "master" database.
In summary:
If you have a true master/slave relationship, it's fairly trivial. If you really wanted to do it by brute force, you'd just dump the entirety of all the MySQL data tables to text files, delete all the records in your Access data store and import the text files.
I would tend not to do that, as the first time you need to depart from the pure master/slave relationship, you're hosed and have to rewrite everything from scratch.
The outline I gave above will work very cleanly for master/slave, but will also work well if you have a few fields that are private to the "slave" database, or data that exists in the slave and not in the master (which is the situation I was working with).