I am trying to change a text field to a number field, however, any attempt to make changes is met with the same error. Apparently this field is part of a relationship. I've looked through everything. The relationship window shows no connection to this field. I have selected the show "All Relationships" button, but still nothing. Another similar question stated that the relationship was found in a report, but I have not yet created any reports. I could just copy everything into a new project, or even just delete and recreate the one table, but if anyone can help me out, I'd much rather learn something here.
You could use VBA to examine the Relations collection. I don't know if it will identify your missing relationship, but it should be easy to find out.
Paste this code into a standard module, run it, and review the output in the Immediate Window:
Public Sub InspectRelations()
Dim rel As DAO.Relation
Dim fld As DAO.Field
For Each rel In CurrentDb.Relations
Debug.Print "Relationship Name: " & rel.Name
Debug.Print "Table: " & rel.Table
Debug.Print "ForeignTable: " & rel.ForeignTable
For Each fld In rel.Fields
Debug.Print "Field Name: " & fld.Name
Debug.Print "ForeignName: " & fld.ForeignName
Next fld
Debug.Print String(10, "-")
Next rel
Set fld = Nothing
Set rel = Nothing
End Sub
You can try the following:
Besides clicking on "All Relationships" in the relationship view, add your tables manually and see if any new relationships show up.
Another nice way to find out about all dependencies of your table click on it and choose "Object Dependencies" under Database Tools. You could have created relationships in Queries, in Forms (Data Sources) and in Reports - just check the dependent objects.
Related
I want users to be able to provide a query they made in the GUI, using a combo box, and then load that query into a recordset to do further processing on it. This fails if the query contains a user-defined function or form-based parameter.
My code looks like this:
Private Sub cmbSelectionColumn_AfterUpdate()
Dim r As DAO.Recordset
Set r = CurrentDb.OpenRecordset("SELECT DISTINCT " & EscapeSQLIdentifier(Me.cmbSelectionColumn.Value) & " FROM " & EscapeSQLIdentifier(Me.cmbSelectionTable.Value))
Do While Not r.EOF
'Do stuff
r.MoveNext
Loop
End Sub
Where cmbSelectionColumn is a user-selected column, and cmbSelectionTable is a user-selected table or query, and EscapeSQLIdentifier is a function that escapes and adds brackets to ensure the field and tablename are safe. This mostly works fine, but it fails in multiple cases, such as involving pass-through queries, user-defined functions, and form-based parameters.
Is there a way I can create a recordset from any query that works in Access, without having to worry about this?
Yes, there is, but you will have to do some trickery.
Forms support these queries just fine. And forms have a .RecordsetClone property that allows us to retrieve the recordset.
To allow us to retrieve the recordset from code, we're going to create a new blank form, and add a module to it (in fact, any form with a module will do). We'll name it frmBlank.
Then, we can adjust the code to use this form to retrieve the recordset.
Private Sub cmbSelectionColumn_AfterUpdate()
Dim r As DAO.Recordset
Dim frm As New Form_frmBlank
frm.RecordSource = "SELECT DISTINCT " & EscapeSQLIdentifier(Me.cmbSelectionColumn.Value) & " FROM " & EscapeSQLIdentifier(Me.cmbSelectionTable.Value)
Set r = frm.RecordsetClone
Do While Not r.EOF
'Do stuff
r.MoveNext
Loop
End Sub
This allows us to retrieve the recordset. The form will not pop up (since we haven't set .Visible to True), and will close once the code is done running since there is no active reference to it. I haven't yet seen any tables or queries that do work in Access, but do not work with this approach, and the performance penalty is minor. It does make for odd code and an odd blank form with blank module that will cause your database to malfunction when deleted.
The following may present an alternative approach to opening DAO recordsets which reference form-based parameters:
Dim db As DAO.Database
Dim pr As DAO.Parameter
Set db = CurrentDb
With db.CreateQueryDef("", "SELECT DISTINCT " & EscapeSQLIdentifier(Me.cmbSelectionColumn.Value) & " FROM " & EscapeSQLIdentifier(Me.cmbSelectionTable.Value))
For Each pr In .Parameters
pr.Value = Eval(pr.Name)
Next pr
With .OpenRecordset
If Not .EOF Then
.MoveFirst
Do Until .EOF
' Do stuff
.MoveNext
Loop
End If
.Close
End With
End With
Here, since references to objects outside of the scope of the query (such as references to form controls) become query parameters whose parameter name matches the original reference, the parameter name is evaluated to yield the value held by the form control, and the parameter value is then updated to the result of this evaluation.
The problem I'm facing:
I try to check if inserted text from multiple text boxes is already existing in a table before saving the records to avoid duplicates.
I created a form to enter new members and save them into a table. The key to avoid duplicates is to check the combination of given name, last name and birth date with existing records. (It's most likely that there won't be two person with all three criteria matching)
I have no problem to check the existence for only one text box by setting the focus on the desired box and use the SQL query IF EXISTS...
But since I would need to set focus on several text boxes(IMO) the problem occurs.
Is there a way to set focus on multiple text boxes?
The idea would be to use an IF EXISTS...AND EXISTS statement and I would need to implement the .SetFocus statement for each text box before checking its existence.
I hope you get my point and I would be glad if someone could share some knowledge. :)
Thanks in advance
There seems to be some missing information in order to find the best solution to your problem. so the below response will be based on assumptions as to how your form is working.
I'm assuming you are using an unbound form with unbound text boxes? if this is the case, then you must have a button that is the trigger for checking/adding this information to your table. lets say your command button is called "Save". You can use the following code without the need to .setfocus to any textbox.
Private Sub Save_Click()
Dim db as DAO.Database
Dim rst as DAO.Recordset
Dim strSQL as string
set db = currentdb 'This is the connection to the current database
'This is the SQL string to query the data on your table
strsql = "SELECT * " & _
"FROM [Yourtablename] " & _
"WHERE ((([YourTableName].[FirstName]) ='" & me.FormFirstNameField & "' AND ([YourTableName].[LastName]) ='" & me.FormLastNameField & "' AND ([YourTableName].[DOB]) =#" & me.FormDOBField & "#));"
set rst = db.openrecordset(strsql) 'This opens the recordset
if rst.recordcount <> 0 then
'Enter code to inform user information already exists
else
'Enter code if information does not exits
end if
rst.close 'Closes the recordset
set rst = nothing 'Frees memory
set db = nothing 'Frees Memory
End Sub
Let me know if this code works or if I need to make changes based on your scenario.
I have an access web database that several users will need to log in to. The database contains a table of products.
The challenge is, every user needs to only see a subset of these products and never see the whole list.
At the moment i have some code to modify an existing query based on the logged in user's details. As they log in, some tempvars are created and these are used to modify the query criteria.
This works well when the first user logs in, but the moment the next user logs in, the query is modified again and the product list refreshes and now his products are shown and not the first users! Im thinking i need to dynamically create a permanent query for each user on log in?
Or is a better way to accomplish what im trying ? im quite new to access and struggling. Can anyone assist please?
Here is my code so far:
Button on login form has the following code that collects the user's details
Private Sub cmdLoginMine_Click()
Dim ID as long, strEmpName as string,strZondsc as string,strgrpdsc as string
ID = DLookup("ID", "Employees", "Login='" & Me.txtUser.Value & "'")
strEmpName = DLookup("FullName", "Employees", "Login='" & Me.txtUser.Value & "'")
strgrpdsc = DLookup("MyGrpdscs", "Employees", "Login='" & Me.txtUser.Value & "'")
strzondsc = DLookup("MyZondscs", "Employees", "Login='" & Me.txtUser.Value & "'")
TempVars.Add "tmpEmployeeID", ID
TempVars.Add "tmpEmployeeName", txtUser.Value
I then call a function that modifies the existing query, populating it with this users details for the criteria
qryEdit strgrpdsc, strzondsc, ID
Sub qryEdit(strgrpdsc As String, strzondsc As String, ID As Long)
Dim qdf As DAO.QueryDef
Dim qdfOLD As String
Set qdf = CurrentDb.QueryDefs("InventoryQryforDS")
With qdf
.SQL = "SELECT Products.ProductCode, Products.ProductName, Products.GRPDSC, Categories.Category, Inventory.Available " & _
"FROM (Categories INNER JOIN Products ON Categories.ID = Products.CategoryID) INNER JOIN Inventory ON Products.ID = Inventory.ProductID " & _
"WHERE Products.GRPDSC in (" & strgrpdsc & ") and Categories.Category in (" & strzondsc & ") and products.ownersid =" & ID & _
" ORDER BY Products.ProductCode"
End With
Set qdf = Nothing
End Sub
The results of the query are shown on a form, which is what is currently requerying and showing the wrong data.
Thanks
EDIT - THe data is shown on a form, linked to one of the new style navigation buttons as shown.The recordsource property of the form is the query that's populated as described above.
I have a few suggestions/corrections to your approach to solving this issue.
When using DLookup, make sure they are enclosed within Nz() function, if the value you are looking for is not found you might be facing troubles of assigning a Null value to a Data Type that cannot handle Null. Anything other than Variant type will suffer.
You seem to do not one but four DLookup's on the table. This could be very expensive. This could be minimized by using a simple RecordSet Object.
I would not use TempVars much as they could be tricky to understand and implement.
Why are you editing the Query? This could again be a bit expensive in terms of memory. How are you showing the list of Products? In DataSheet or ComboBox or LsitBox? You could yet again change the RecordSource or RowSource of the Objects rather than editing the Query itself.
Finally, your users should all have a separate copy of the Front End file. Not one copy used by 20-30 people. If the files is restricted to be used by one person, then the code should work regardless of being modified. As the user will have access to the right data at all times.
So, I have a MS Access database application. In this application is a main form, which contains a number of subforms. One form in particular has a drop down box that I populate with dates from a database query. When one of these dates is selected, I run a subroutine that is supposed to update a recordset on the subform with history information. Below is some edited code (just removed the large number of fields from the queries)
Private Sub pickdate_AfterUpdate()
'''''''''''''''''''''''''''''''''''''''''
' Add review history by selected date
'''''''''''''''''''''''''''''''''''''''''
Dim rs As Recordset
Set rs = CurrentDb.OpenRecordset("SELECT model, entered_date FROM history WHERE entered_date=#" & Me.pickdate.value & "# ORDER BY model DESC", dbOpenDynaset, dbSeeChanges)
If rs.BOF = False Then rs.MoveFirst
While rs.EOF = False
Forms!main!histories.Form.Recordset.AddNew
Forms!main!histories.Form.Recordset![model] = rs![model]
Forms!main!histories.Form.Recordset![entered_date] = rs![entered_date]
Forms!main!histories.Form.Recordset.Update
rs.MoveNext
Wend
End Sub
I get the error on the Forms!main!histories.Form.Recordset.AddNew line.
I have tried the following versions of that line:
Forms!main!histories.Form.Recordset.AddNew
main!histories.Form.Recordset.AddNew
histories.Form.Recordset.AddNew
Me.Form.Recordset.AddNew
Me.Recordset.AddNew
Me.AddNew
Me.main!histories.Form.Recordset.AddNew
Me!histories.Form.Recordset.Addnew
Me!main!histories.Form.Recordset.AddNew
I am literally at my wit's end trying to figure out where the issue is.
The subform has all the proper boxes to store the information. I have given them labels to match their database columns that will go into them. I've tried setting their control sources to the database column names and not setting them to anything. I've looked up a hundred different "solutions", none of which seem to either fit the problem or work.
I feel like I am overlooking something really easy.
I reckon you have problems with your names. Check all of them. Do not forget that a subform consists of two parts, the subform control and the form contained. These often have the same name, but not always. In the code you are using, you must have the name of the subform control, not the form contained. If entering data into the subform manually is not working properly, your controls are not bound.
This works for me on a sample table.
Dim rs As Recordset
Set rs = CurrentDb.OpenRecordset("SELECT atext from table1 WHERE akey=21")
If rs.BOF = False Then rs.MoveFirst
While Not rs.EOF '= False
Me.Table1_subform1.Form.Recordset.AddNew
Me.Table1_subform1.Form.Recordset!AText = rs!AText
Me.Table1_subform1.Form.Recordset.Update
rs.MoveNext
Wend
To run a query you could say:
sSQL="INSERT INTO NameOfTable (model, entered_date) " _
& "SELECT model, entered_date FROM history WHERE entered_date=#" _
& Me.pickdate.value & "#"
CurrentDB.execute, dbfailOnError
You can check the sql works in the query design window.
I'll start with the background story before explaining the problem with my code. I'm using MS Access 2010. I've been able to import a table of data with two columns. Then I was able to curate the data by adding fields with appropriate values to the imported table. Now, I need to take the curated table and integrate it into my data base. However, I cannot use any of Microsofts built in queries as none of these appear to be able to do what I need. The integration breaks the table apart, yes, but it needs to preserve the relationships of the data in each record.
To this end I've been writing some code in VBA:
Function IntegrateNIRData(curatedTable, queryRecords)
On Error GoTo Error_Handler
Dim db As DAO.Database
Dim rsCuratedTable, rsDBRecords As DAO.Recordset
Dim iCount As Integer
Set db = CurrentDb()
Set rsCuratedTable = db.OpenRecordset(curatedTable, dbOpenTable) 'open the recordset for use (table, Query, SQL Statement)
Set rsDBRecords = db.OpenRecordset("NIR_Samples_verify", dbOpenDynaset, dbExecDirect, dbOptimisticValue)
With rsCuratedTable
If Not (.BOF And .EOF) Then
Do While Not .EOF
' Rest of your code here.
rsDBRecords.AddNew
'Assign Fields here.
rsDBRecords![Product Name] = rsCuratedTable![productName]
rsDBRecords![Lot Number] = rsCuratedTable![lotNumber]
rsDBRecords!counts = rsCuratedTable![counts]
rsDBRecords![subsets] = rsCuratedTable![subsets]
rsDBRecords![Date Taken] = rsCuratedTable![dateTaken]
rsDBRecords.Update
rsDBRecords.Bookmark = rsDBRecords.LastModified
.MoveNext
Loop
End If
End With
rsCuratedTable.Close 'Close the recordset
rsDBRecords.Close 'Close the recordset
Error_Handler_Exit:
On Error Resume Next
'Cleanup after ourselves
Set rs = Nothing
Set db = Nothing
Exit Function
Error_Handler:
MsgBox "MS Access has generated the following error" & vbCrLf & vbCrLf & "Error Number: " & _
Err.Number & vbCrLf & "Error Source: IntegrateNIRData" & vbCrLf & "Error Description: " & _
Err.Description, vbCritical, "An Error has Occured!"
Resume Error_Handler_Exit
End Function
The Function hangs on this line, the second OpenRecordset:
Set rsDBRecords = db.OpenRecordset("NIR_Samples_verify", dbOpenDynaset, dbExecDirect, dbOptimisticValue)
To my understanding this may have something to do with Workspaces and the Jet engine not accepting a ms query that spans multiple tables. Of course, I could also be way off. Any advice at this point would be greatly appriciated.
Update:
Several of you have asked similar questions so I felt I should clarify the following:
1) NIR_Samples_verify is an MS access select query that generates a table of records from several of the tables in the database.
2) I keep getting two errors depending on what I set the RecordsetOptionEnum and LockTypeEnum to in the OpenRecordset method.
One is Error Number 3027 Database is Read-Only
Two is Error Number 3001 Invalid Arguement
3) To my understanding the rest of the code should be fine, it is just the OpenRecordset method that is causing the problem.
Update 2:
I am thinking that maybe access is not capable of doing what I would like. Let me illustrate. If I had two tables both with primary keys and these keys are referenced in a third table that links the two tables causing a many-to-many relationship, then the code would have to not only add the new data to the two tables, but also generate an appropriate record in the third table to maintain the relationship in the data. Hope that makes since. I do appriciate the help and experience.
Update 3:
Have been searching the net and found the following:
From this post it says the query is only updatable when:
1) It is based on a single table.
2) It is based on a query based on a single table.
3) It is based on a query based on tables with a one-to-one relationship.
Not knowing what the contents of NIR_Samples_verify are, I'd be highly suspicious of the dbExecDirect
From the help file
dbExecDirect
"Runs a query by skipping SQLPrepare and directly calling
SQLExecDirect (ODBCDirect workspaces only). Use this option only when
you’re not opening a Recordset based on a parameter query. For more
information, see the "Microsoft ODBC 3.0 Programmer’s Reference." "
I don't see you supplying any parameters.
-- Edit --
Typically I'll open a record set like this
Set rsDBRecords = db.OpenRecordset("select bar from foo where bar > 10", _
dbOpenDynaset, _
dbSeeChanges)
(Especially if I want to alter the data init)
Hopefully that'll move you further in your project.
-- Edit 2 --
It sounds like NIR_Samples_verify is to complicated to be edited. Actually, given that it is a join of multiple tables doing an Add on it doesn't make much sense, and Update MIGHT make sense in some cases.
Your ultimate solution is really going to be doing multiple Adds on multiple record sets (one for each table being referenced in NIR_Samples_verify); much like if you were entering the data into the DB by hand. You add the records that aren't dependant on anything else first (remembering to grab keys to use in the dependant tables).
As it turns out my hunch was correct. The problem had to do with MS Access having updatable and non-updatble queries (See my edits of the question). The main problem was not only does Microsoft not make this information apparent, but there is no master list on their site either. Thank you everyone for the help. Feel free to see this article for more details.