Control Rights to Linked Tables in MS-Access - ms-access

I'm afraid I already know the answer to this, but I'm checking with the community in case there's something I don't know about....
Is it possible to have the MS Access table linking feature control rights to linked tables? Secifically, can FE.accdb have read/write privileges on BE_A.accdb, but read-only links to BE_B.accdb (without making BE_B.accdb entirely R/O)?

Sort of.
Quoting David Fenton from a post earlier this year on another forum:
One way would be to remove the linked
tables, and create queries to replace
them (you could use the same name for
the query as the corresponding linked
tables), and use a connect string in
the query and set the recordset type
to snapshot, which will be read-only
by default.
I just recently had occasion to do this myself. I asked a related question about setting the querydef recordset type to snapshot via VBA here.
You can adapt the following code to do what you need:
Sub ReadOnlyLink(MDBPath As String, TblName As String, SrcTblName As String)
Dim q As DAO.QueryDef
Set q = CurrentDb.CreateQueryDef(TblName, "SELECT * FROM " & SrcTblName & _
" IN """ & MDBPath & """")
q.Properties.Append q.CreateProperty("RecordsetType", dbByte, 2)
End Sub

This isn't really an answer, but it's too long for comments. Thoughts sparked by the answer I accepted.
It seems that it should be possible to use this for user-level "security":
Set up a BE
Set up a distributable FE with deliberately broken links
in the FE startup, get user name (API calls)
Run user name through a Select Case, re-linking as either real table or querydef as appropriate. Might be even better to do it with a user name -> role lookup before the Select.
Hmmm. Have to think about that some more.... Not bulletproof, but not really intended to be. More a way of dividing responsibility for updates to the users that are the respective domain experts. Don't know if it's really justified.

Related

Access: 2 roles on the same DB with different roles

I have an Access Database on the SharePoint and two user's roles that have to work on it:
Role1 is given to a single user. He can manage all the forms of the DB with the possibility to change all the tables. These forms will require many future releases.
Role2 is given to many users. They can manage only one form that is effective only on a single table of the DB. He doesn't (and mustn't) need to see/manage the others forms/tables (they are a lot). The form used for this role will not require future releases.
What it the best practice to manage this? I thought about the following 2 solutions but probably there is a third one that is better.
Solution #1
Having 2 different Access files linked to the same DB: one with all the forms (that I give to Role1) and one with only one form (that I give to Role2).
Solution #2
Having a single Access file that I give to both the users. Role1 has read/write access to all forms. Role2 can see only a specific form and has no read/write access to other forms.
I would recommend solution #2 otherwise if you change the logic in the front end you have to change it always twice and this is really annoying. Also, if you forget to change both versions and you had a huge change in the logic, you have people working with the old version and people working with the new version.
What I normally do is the following. I have a table tblDeveloperAccess with the ID of your Role1. At the start of the first form load event I have the following code:
Dim db As Database
Dim rs As Recordset
Set db = CurrentDb
Set rs = db.OpenRecordset("tbDeveloperAccess", dbOpenSnapshot)
rs.FindFirst "ID = '" & Environ("USERNAME") & "'"
If rs.NoMatch Then
DoCmd.NavigateTo "acNavigationCategoryObjectType", "acNavigationGroupTables"
DoCmd.SelectObject acForm, vbNullString, True
DoCmd.RunCommand acCmdWindowHide
DoCmd.ShowToolbar "Ribbon", acToolbarNo
End If
Basically I am hiding the ribbon and the object navigation. You can go even further and disable the context menu and the "Shift + DblClick"-Trick (on your database file). And of course I disable the possibilty on the start form to get into the design view.

Issue with an if-statement

I'm trying to use a macro to check and see if there are records left within a table, and if there are, then display a message, letting me know there is still data in the table. My set up looks like this
Currently, I'm getting this error message:
I get this error message regardless of whether I use Is Not Null or Not IsNull. Is there any suggestions as to what I'm doing wrong?
Macros is one of the, if not the, most annoying topics in Access. It illustrates beautifully one of the most galactically stupid aspects of Access: it cheerfully allows you to point to and select a table by name and a field name to boot giving you the false hope that it actually knows what you are talking about then turns around and tells you it has no idea what you are asking for. Brilliant. Not only does the "red headed step child" that is Access get mismatched shoes, neither of them fit!
I honestly thought this would be easy to answer. But to add insult to injury, Microsoft has documented this poorly conceived "feature" about as well as they have implemented it.
I'm not sure I understand exactly what you are trying to do but I think you simply want to know if a table is empty. If so, my suggestion: use a function. For example:
Function IsTableEmpty(aTableName As String) As Boolean
Dim rst As DAO.Recordset
Set rst = CurrentDb.OpenRecordset("select count(*) from [" & aTableName & "];", dbOpenForwardOnly, dbReadOnly)
IsTableEmpty = rst.Fields(0) = 0
rst.Close
Set rst = Nothing
End Function
If you insist on using a macro you will be astonished to find that Access can find your function and use it with no difficulty. You can use this with any table (query for that matter).
Sadly, if you are doing web applications with Access you are going to have to come to grips with whatever (lame) functionality macros provide because VBA will not be available to you.
HTH. Good luck.
PS - I would happily eat my words if someone would point me to the documentation that explains how this works and why such a situation exists!

Writing a single column from a table in MS Access VBA to .txt file

this is my first time posting a question here, but I almost always get good answers from searching this site. I'm trying to find out if there is a better way to speed up this process I have of writing a table column in Access to a .txt file. Here is the code I have, which works, but it's on the slow side. It takes about 45s to write around 7000 items.
lsFileName2 = "E:\DOI_Inventory2\SyncData\EquipUser.txt"
LiFileNumb = FreeFile
SysCmd acSysCmdSetStatus, "Updating User Equipment List"
Open lsFileName2 For Output As LiFileNumb
With rst
Do While Not .EOF
Write #LiFileNumb, ![EqUserFile]
.MoveNext
Loop
End With
dbs.Close
Close LiFileNumb
I'm fairly new to the IT field so any help would be greatly appreciated. Thanks
Just to add a note, the actual query is fine. I already checked that and it's pretty fast.
Create a query, save it with a name, and then use TransferText to export the query's data to your text file.
So assuming you have a SELECT query named qryExportMe like this which returns your table's column data correctly ...
SELECT EqUserFile
FROM YourTable;
... refer to this TransferText example and adapt it to fit your needs.
DoCmd.TransferText TransferType:=acExportDelim, _
Tablename:="qryExportMe", _
FileName:="E:\DOI_Inventory2\SyncData\EquipUser.txt", _
HasFieldNames:=True
Check the TransferText options at that linked page or from Access' built in help system.
Note you are not required to include the option names. I added them to help you keep track of which is which.
If this approach speeds up your export operation adequately, I think it will be because Access handles the task as a single set-based file write. Your recordset approach required Access to process one row at a time ... and one reason such approaches are called RBAR (row by agonizing row) is because they are often painfully slow.

How to find broken queries in Access?

How do I find broken queries in access.
i.e. Queries that might have broken because the underlying table was deleted or the name of the column in the table changed?
Is there an easy way -- rather than just opening each query running and checking if something has gone wrong?
Here are a few notes that may be of interest, depending on your version of Access.
See: GetDependencyInfo Method [Access 2003 VBA Language Reference]
Do not forget that Track name AutoCorrect info is not a good thing, for the most part, but can be useful in certain circumstances.
Dim dinf As DependencyInfo
For j = 0 To CurrentData.AllQueries.Count - 1
Set dinf = CurrentData.AllQueries(j).GetDependencyInfo
For i = 0 To dinf.Dependencies.Count - 1
''Missing alias, query or table, as far as I can tell
If dinf.Dependencies.Item(i).Name Like "MISSING:*" Then
Debug.Print CurrentData.AllQueries(j).Name _
& " " & dinf.Dependencies.Item(i).Name
End If
Next
Next
You may need to update dependencies:
Application.CurrentProject.UpdateDependencyInfo
This will require a save.

Can I compare two ms-access files? [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking us to recommend or find a tool, library or favorite off-site resource are off-topic for Stack Overflow as they tend to attract opinionated answers and spam. Instead, describe the problem and what has been done so far to solve it.
Closed 9 years ago.
Improve this question
I want to compare two ms-access .mdb files to check that the data they contain is same in both.
How can I do this?
I've done this kind of thing in code many, many times, mostly in cases where a local MDB needed to have updates applied to it drawn from data entered on a website. In one case the website was driven by an MDB, in others, it was a MySQL database. For the MDB, we just downloaded it, for MySQL, we ran scripts on the website to export and FTP text files.
Now, the main point is that we wanted to compare data in the local MDB to the data downloaded from the website and update the local MDB to reflect changes made on the website (no, it wasn't possible to use a single data source -- it was the first thing I suggested, but it wasn't feasible).
Let's call MDB A your local database, and MDB B the one you're downloading for comparison. What you have to check for is:
records that exist in MDB A but not in MDB B. These may or may not be candidates for deletion (this will depend on your particular data).
records that exist in MDB B but not in MDB A. These you will append from MDB B to MDB A.
records that exist in both, which will need to be compared field by field.
Steps #1 and #2 are fairly easily accomplished with queries that use an outer join to find the missing records. Step 3 requires some code.
The principle behind the code is that the structure of all the tables in both MDBs are identical. So, you use DAO to walk the TableDefs collection, open a recordset, and walk the fields collection to run a SQL statement on each column of each table that either updates the data or outputs a list of the differences.
The basic structure behind the code is:
Set rs = db.OpenRecordset("[SQL statement with the fields you want compared]")
For Each fld In rs.Fields
' Write a SQL string to update all the records in this column
' where the data doesn't match
strSQL = "[constructed SQL here]"
db.Execute strSQL, dbFailOnError
Next fld
Now, the major complexity here is that your WHERE clause for each field has to be different -- text fields need to be treated differently from numeric and data fields. So you'll probably want a SELECT CASE that writes your WHERE clause based on the field type:
Select Case fld.Type
Case dbText, dbMemo
Case Else
End Select
You'll want to use Nz() to compare the text fields, but you'd use Nz(TextField,'') for that, while using Nz(NumericField,0) for numeric fields or date fields.
My example code doesn't actually use the structure above to define the WHERE clause because it's limited to fields that work very well comparing concatenated with a ZLS (text fields). What's below is pretty complicated to read through, but it's basically an expansion on the above structure.
It was written for efficiency of updates, since it executes a SQL UPDATE for each field of the table, which is much more efficient than executing a SQL UPDATE for each row. If, on the other hand, you don't want to do an update, but want a list of the differences, you might treat the whole thing differently. But that gets pretty complicated depending on the output,
If all you want to know is if two MDBs are identical, you would first check the number of records in each table first, and if you have one non-match, you quit and tell the user that the MDBs aren't the same. If the recordcounts are the same, then you have to check field by field, which I believe is best accomplished with column-by-column SQL written dynamically -- as soon as one of the resulting SQL SELECTS returns 1 or more records, you abort and tell your user that the MDBs are not identical.
The complicated part is if you want to record the differences and inform the user, but going into that would make this already-interminable post even longer!
What follows is just a portion of code from a larger subroutine which updates the saved query qdfOldMembers (from MDB A) with data from qdfNewMembers (from MDB B). The first argument, strSQL, is a SELECT statement that is limited to the fields you want to compare, while strTmpDB is the path/filename of the other MDB (MDB B in our example). The code assumes that strTmpDB has qdfNewMembers and qdfOldMembers already created (the original code writes the saved QueryDef on the fly). It could just as easily be direct table names (the only reason I use a saved query is because the fieldnames don't match exactly between the two MDBs it was written for).
Public Sub ImportMembers(strSQL As String, strTmpDB As String)
Const STR_QUOTE = """"
Dim db As Database
Dim rsSource As Recordset '
Dim fld As Field
Dim strUpdateField As String
Dim strZLS As String
Dim strSet As String
Dim strWhere As String
' EXTENSIVE CODE LEFT OUT HERE
Set db = Application.DBEngine(0).OpenDatabase(strTmpDB)
' UPDATE EXISTING RECORDS
Set rsSource = db.OpenRecordset(strSQL)
strSQL = "UPDATE qdfNewMembers INNER JOIN qdfOldMembers ON "
strSQL = strSQL & "qdfNewMembers.EntityID = qdfOldMembers.EntityID IN '" _
& strTmpDB & "'"
If rsSource.RecordCount <> 0 Then
For Each fld In rsSource.Fields
strUpdateField = fld.Name
'Debug.Print strUpdateField
If InStr(strUpdateField, "ID") = 0 Then
If fld.Type = dbText Then
strZLS = " & ''"
Else
strZLS = vbNullString
End If
strSet = " SET qdfOldMembers." & strUpdateField _
& " = varZLStoNull(qdfNewMembers." & strUpdateField & ")"
strWhere = " WHERE " & "qdfOldMembers." & strUpdateField & strZLS _
& "<>" & "qdfNewMembers." & strUpdateField & strZLS _
& " OR (IsNull(qdfOldMembers." & strUpdateField _
& ")<>IsNull(varZLStoNull(qdfNewMembers." _
& strUpdateField & ")));"
db.Execute strSQL & strSet & strWhere, dbFailOnError
'Debug.Print strSQL & strSet & strWhere
End If
Next fld
End If
End Sub
Code for function varZLSToNull():
Public Function varZLStoNull(varInput As Variant) As Variant
If Len(varInput) = 0 Then
varZLStoNull = Null
Else
varZLStoNull = varInput
End If
End Function
I don't know if that's too complex to make sense, but maybe it will help somebody.
You can try AccessDiff (paid product). It has the ability to compare the schema, the data, and also access objects. It has a GUI and also a command line interface.
Disclosure: I am the creator of this tool.
Take text dumps of database tables and simply compare the dumped text files using BeyondCompare (or any other text comparison tool). Crude but can work!
I have very good experience with Cross-Database Comparator. It is able to compare structure and/or data.
See the Compare Access databases section at the Microsoft Access third party utilities, products, tools, modules, etc. page at my website.
I've added "table diff" feature to my accdbmerge utility not so long time ago.
I beleive that this answer will not help to solve original question, but it may be helpful for someone faced with the same problem in the future.
If you want to know if the files are identical then
fc file1.mdb file2.mdb
on a DOS command line.
If the files aren't identical but you suspect they contain the same tables and records then the easiest way would be quickly write a small utility that opens both databases and cycles through the tables of both performing a heterogeneous query to extract the Diff between the two files.
There are some tools out there which will do this for you, but they all appear to be shareware.