Connect multiple tables in Access - database

I want to connect multiple tables in Access. I have a main table and then multiple smaller tables that I would like to connect. Each row in the main table belongs to one entire sub-table. I would like to have small + appear next to each row in the main table and showing the sub-tables upon clicking on the +.
I tried this via relationships but it only works for the first row (perfectly) but not for any other rows. When clicking on the other rows, they are empty and no sub-table is opening up.
Any ideas?

Per the comments if you must do this here is an example:
example main table and sub tables
example form created from the main table using the create form wizard and selecting tabular to get a better looking starting form:
note I added an unbound button to the details section and that button gets replicated for each row of data. I will show two ways of setting up the button to open the correct form.
put the form in design mode open the button's properties and open the onclick event. you can do this with the macro language but I show the code:
Private Sub openButton_Click()
'each button the detail section creates has access to the data or controls in the buttons row
DoCmd.OpenTable Me.subTableName 'if form use .OpenForm
'DoCmd.Close acForm, "mainForm" 'if want to close main form
'OpenTable (MainID)
End Sub
if the logic behind opening the form gets complicated I suggest abstracting the logic to a function. here use OpenTable instead and add the Public OpenTable function inside a code module.
Public Function OpenTable(tableID As Long) As Boolean 'function allows the option checking the return value to test if OpenTable worked
Select Case tableID
Case 1
DoCmd.OpenTable "subTable1"
Case 2
DoCmd.OpenTable "subTable2"
Case 3
DoCmd.OpenTable "subTable3"
End Select
OpenTable = True
End Function
Note: you could expand the form's header and show the mainTable as a subform in that header. Then you could add a button next to each row in that subform but outside the subform. The approach I show is easier to maintain.

Related

MS Access Foreign Key Record Fill Too Fast

I have a problem with one of my forms in my MS Access database, and strangely it's the only form that has this problem.
The form has a typical Master/Detail structure, with the subform tied to a table. The subform record source includes a foreign key that pulls information from another table and populates the rest of the fields based on the key value. This foreign key is a Material number that defines a specific object in an inventory, and the other fields in the subform show details of this object.
Example from Signs table:
Material number: 116063175
StorageBin: A116
Material Description: Stop Sign
Dimensions: 48x48
All of this information is contained in the same table, but the form is for a table that is used to fill in what signs are on a particular road (stops, speed limits, etc.)
On all my other forms, when I type in the material number and shift focus anywhere else, the rest of the forms will fill in automatically. This process works here too, but for some reason Access wants to try to fill in the rest of the field data before I have finished typing the material number. I'll type "1" and access will throw an error that it cannot find a matching record in the Signs table in the foreign key's table. After rejecting the error twice, the data entry can resume as normal, which is also strange.
I hope I've been clear enough, this is my first time asking a question here.
Thanks in advance!
Edit: Tried re-building the form, same issue. Built another form similar but without my multiple comboboxes, didn't have the issue! Could this be due to underlying requery code in the Afterupdate event of my comboboxes? I have a cascading combobox setup on the form, could data entry be triggering a requery?
Edit2: for the time being, a fix that I am using is to make the material number and quantity (the two important fields for this form) into text boxes outside the subform, that the user can edit then place in the subform with a button click, which is coded as so:
Private Sub Command1_Click()
If Me!PrimaryRoadInventorySubform.Form.Dirty Then
Me!PrimaryRoadInventorySubform.Form.Dirty = False
End If
Me!PrimaryRoadInventorySubform.SetFocus
DoCmd.GoToRecord , , acNewRec
Me!PrimaryRoadInventorySubform.Form!MaterialNumber = MaterialNumtxt
Me!PrimaryRoadInventorySubform.Form!Quantity = Quantitytxt
End Sub

Clear Access Form fields for Insert

I have done doing form in access for inserting records.
When open that form the field inside it appear filled with previous record l want them to be empty for allowing the user fill the filed, what should I do please!
If you just want to go to a new record just use the following in the load event
private sub yourformname_load()
docmd.gotorecord acdataform,"yourformname", acNewRec
'or
'docmd.gotorecord ,, acNewRec
To keep them from viewing previous records
me.navigationbuttons = false
To allow them to view just not edit previous records
me.allowedits = false
If you want to go to another new record when they click the ok button just put the same docmd... in the Click event of your button.

How do you use the SQLQuery component to run multiple queries?

I have a ListBox showing all the records for a single field (first) in a database. When users click the ListBox item I'd like the value for a different field in the db (last), same record, to be displayed. My code ListBox OnClick event code is:
SQLQuery2.SQL.Text:='SELECT * FROM Names WHERE first= :FIRST';
SQLQuery2.Params.ParamByName('FIRST').AsString := ListBox1.Items[ListBox1.ItemIndex];
SQLQuery2.Open;
ShowMessage('You selected '+SQLQuery2.FieldByName('last').AsString);
When you click an item, the expected field comes up in the MessageBox. However, if you then click a different item, nothing changes--the MessageBox shows the original field.
I don't know enough about SQLQuery components and how they interact with the underlying db to know what's happening.
[P.S. The db is sqlite3, if that matters, and I'm using Lazarus rather than Delphi, if that matters.]
You need to close your query before opening it again. If you look at the code for Open on TDataSet it sets the Active property to true. The setting code for Active first checks that the value is different before doing any work:
procedure TDataSet.SetActive(Value: Boolean);
begin
..
if Active <> Value then
begin
end;
end;
So in your case, the active property is already true and the code just exits.

MS Access keep ID field in subform filled with ID from parent form

Everytime I jump to where I can enter e new record, the ID field from the parent is empty and so the connection is lost. I am looking for a workaround.
My Setup
I have a parent form that deals with two 1:n relationships
(school-class --> pupils, school-class --> tests).
For the first relationship I used the wizard. Everything works find. For the second I show the connected tests in an unbound list. Under the list is a button opening the form for entering a new record (test) for the class I came from (parent form). So I filter the sub-form via VBA so that only the tests of the current class are shown. That works perfectly fine, too.
When moving through the tests already connected with the class the correct ID (of the class filtered) is the value of the corresponding input field. But when I come to the new new record state (all fields empty), then the connection to the parent breaks and the user has to manually enter the ID of the parent (school-class).
My Question
Is my setup correct?
Is there a better way to create a subform that offers to (only) enter a new record connected to the parent data? (Maybe without the ID input field in the subform and passing of forcing the value via VBA?)
Thank you for your time!
You can use Default Value to set the classid of Tests form but be sure the parent form is open in background or behind the pop up.
Under Property Sheet/Data tab of Tests form's classid control, enter in Default Value cell:
=Forms!parentformname!classid
Alternatively, in VBA in the Tests form's OnOpen Event:
Me.classid.DefaultValue = Forms!parentformname!classid
You can then choose to hide (Visible - No) this classid control so users do not modify it. It's always advised to never allow users control of primary and foreign keys.

How to force update a DB grid?

I may have been too clever for my own good :-/
I have a table which holds some pressure measurements. These are always stored as PSI, but the user can select a radio group button to toggle between PSI and BAR.
In order to keep the code clean and and push work onto the database, I created a second table for configuration items, with a single row. One column psi_bar_conversion will take the value either 1 or 14.5 as the user toggles the radio group.
In Delphi, my query which ties to my DB grid is set up with statements like
SELECT ROUND(inlet_waterPressure_psi /
(SELECT psi_bar_conversion FROM configuration),
(SELECT float_precision FROM configuration))
AS inlet_waterPressure,
FROM measurements
All of which works just fine (and perhaps I am explaining too much).
All that I am tring to do is add some code in the function which handles the radio button toggle to force my DB grid to refresh its contents becuase I have just updated the value of configuration.psi_bar_conversion (but no direct field of my query, nor of my datasource).
Should I invoke Refresh() or Invalidate() or SomeOtherFunction() - of the DB grid, the query, the datasrouce? That's what is confusing me.
Thanks in advance for any help ....
You need to close and then reopen the query to have the change in psi_bar_conversion and float_precision to take effect. The two sub-selects (for the values from configuration) only happen when the query is executed.
TDBGrid presentation depends on the connected TDataSet (via a TDataSource).
To update the Grid Values you have to refresh the data in TDataSet with the method TDataSet.Refresh.
To update a special Grid you can refresh the connected DataSet like this:
DBGrid1.DataSource.DataSet.Refresh;
But some TDataSet descendants will not refresh and that is documented by Embarcadero
TDataSet.Refresh
It depends on the components you use (i did a test with UniDAC and it works fine)
procedure TForm1.RadioGroup1Click( Sender : TObject );
var
LRate : Extended;
begin
case RadioGroup1.ItemIndex of
0 :
LRate := 1;
1 :
LRate := 14.5;
end;
UniConnection1.ExecSQL( 'UPDATE configuration SET psi_bar_conversion = :conversion', [LRate] );
DBGrid1.DataSource.DataSet.Refresh;
end;
If your components did not refetch the data on calling Refresh, then you have to close and reopen (also stated by documentation)
DBGrid1.DataSource.DataSet.Close;
DBGrid1.DataSource.DataSet.Open;
IMHO such components are not fully implemented, so this is just a workaround having side effects in calling some maybe unwanted events (BeforeClose, AfterClose, BeforeOpen, AfterOpen) which will not get fired using Refresh.
But at all it has nothing to do with SubSelects.
I'm afarid I can't help you with the Delphi side of things here.
On the datbase side of things....
Is there any reason that you can't just store both the bar and psi values in the database?
You could do the conversion when saving and then you are left just to do a simple select on the data when you want to view it. This could be done by the software that is performing the save or by a trigger in the database.
The reason I suggest this is that the psi-bar conversion ratio is not going to change so you are doing a bunch of processing everytime you view the data that is not required...

Resources