ms access: Empty subform query causes empty parent control reference - sql

The Problem
I have two continuous subforms A and B in a tabular layout on a main form C. The first has the names of some chemicals, the second has corresponding info on those chemicals. I have a field D on C that takes the value of the primary key [stoff_id] of A for the current record. B is linked to D, so it shows all corresponding records for the currently selected chemical. Here a quick overview of the database:
DB Relationships
The query for A [stoffe_abfrage subform]:
SELECT chemikalien_tabelle.stoff_id, chemikalien_tabelle.bezeichnung,
chemikalien_tabelle.einsatzgebiet, kategorie_tabelle.kategorie
FROM kategorie_tabelle INNER JOIN chemikalien_tabelle ON
kategorie_tabelle.[kategorie_id] = chemikalien_tabelle.[kategorie_id];
The query for B [tmb_abfrage subform]:
SELECT tmb_tabelle.version, tmb_tabelle.datum_aktualisiert,
tmb_tabelle.datum_upload, sprachen_tabelle.bezeichnung,
tmb_link.stoff_id, tmb_link.tmb_id, tmb_tabelle.datei.FileType,
tmb_tabelle.datei
FROM (sprachen_tabelle INNER JOIN tmb_tabelle ON sprachen_tabelle.
[sprache_id] = tmb_tabelle.[sprache_id]) INNER JOIN tmb_link ON
tmb_tabelle.[tmb_id] = tmb_link.[tmb_id];
The value of the control D [MainLinkStoff] on C:
=[stoffe_abfrage subform].[Formular]![stoff_id]
(B is linked from [stoff_id] on B, to D)
I want to use the primary key value on A in a button event on B, so I need a way to reference it. Unfortunately, referencing the primary key (stoff_id) on A from B only works if B is not empty. If there are no records on B, then the reference of stoff_id on A from B turns empty, event though the value of the control on A itself is nonempty.
What I have tried:
I tried getting [stoff_id] from A and I have
also tried getting the value from D,
but both have resulted in the same issue. When B
currently has no records, I get a runtime error because of an empty
value.
I was curious why this would be the case if getting the value
directly from D for example, since that field has a
value and is never empty. So I made a dummy textbox [dummyB] on
B where my button is located
in the header section and set the value to be equal to
D.
for the second test I tried 2 different approaches:
Get D from C via parent
=[Me].[Parent].[MainLinkStoff]
Get the D value manually from forms
=Formulare![HUB]![NavigationSubform].Formular![MainLinkStoff]
In both approaches, if the chemical already has records in B, the dummy and D both display the value of the primary key correctly and are identical. If the chemical has no current records in B, D on the parent form displays correctly but the dummy is suddenly empty too. Why is this? Here some images of what I mean. D is in the top middle of the form C, the dummy adjacent to it on the right subform B. A is on the left, B on the right. (invisible borders)
Existing records
No existing records

So, I found the issue. I was working on the project from 2 different computers. One used the German language version of Access, the other the English language one. Object references created by wizards and internal tools in those versions use different formulations ([Forms]=[Formulare] etc.). What ended up happening was that some object references in SQL queries, criteria etc. were in German, the objects themselves had further references that were in English, which in turn referenced others that were in German again. This worked most of the time, but quite often, especially in fringe cases, it resulted in Access messing up the references completely. For example in cases where queries or field values were returned empty. I am not entirely sure how Access manages the conversion of references in different language versions, but there seem to be issues with it when mixing them. The solution was to choose one language version to use for references, and stick with that formulation for the entire project. I tested both, and either German or English work fine, on either version of accesss. Mixing them up within the same project however, creates problems.

Related

VB.NET - TableAdapter.Delete() 'Index and length must refer to a location within the string. when deleting record from database'

I have a database with three pairs of tables:
TableA
TableAProspects
TableB
TableBProspects
TableC
TableCProspects
The prospects tables and their respective main tables are identical, except that the mandatory fields in the main tables are not mandatory in the prospects tables, allowing a user to supply incomplete data to the database and piece it together in multiple bits before finally submitting it to the main tables. (Upon submission to the main table the data is validated)
I've created the Select, Insert, Update and Delete queries and the TableAdapters for VB.NET have their methods set up appropriately, seethe code I've used below:
TableATableAdapter.Delete1(TableABindingSource.Current("ID"))
and
TableAProspectsTableAdapter.Delete1(TableAProspectsBindingSource.Current("ID"))
(Delete1 is the name of the method on the TableAdapters)
When I try to delete the records from the Prospects Tables I'm recieving a System.ArgumentOutOfRangeException with the message 'Index and length must refer to a location within the string.' when deleting record from database. This does not happen on the main tables even though the code I've used is identical except me swapping out the respective BindingSources and TableAdapters. While I understand this error message, I don't understand why I'm getting it.
I used a MsgBox to output TableABindingSource.Current("ID") to make sure the ID was correct which it is, I've tried changing it to YProspectsClientsBindingSource.Current.Row("ID") and then tried the latter code by setting an integer variable to this value and then using this variable
Id = TableAProspectsBindingSource.Current.Row("ID")
TableAProspectsTableAdapter.Delete1(Id)
with no success.
I've even tried deleting the TableAdapters from the form and re-inserting them.
While trying to search for answers I've found other questions which appear to be about Substrings (here and here), but I don't understand how that applies with TableAdapters, and why despite using the same code only the prospects tableadapters throw an exception.
The only differences I'm aware of are the contents of the database tables and the names of the TableAdapters and BindingSources.

Count records from another table to include in the results of a bound table

I am using Visual Studio and have an Access database with a couple of tables that are related. They are using default drag/drop binding using WinForms to the dataset which was automatically generated as well.
I want the parent table to include a column with the count of the number of related records with that ID in the results. The tables look like this if it matters:
I added an additional query to the table adapter (as you can see from the screenshot) that does what it needs to do (without including the linked ID's) thinking that was how to do it. Am I at least on the right track? The query looks like this:
SELECT COUNT(*) AS WorkerCount
FROM (tblJobLaborTech INNER JOIN tblJobLabor ON tblJobLaborTech.JobLaborID = tblJobLabor.JobLaborID)
WHERE (tblJobLabor.JobLaborID = 494)
And of course I need to change 494 to something variable which will match the corresponding record when it runs, but
WHERE (tblJobLabor.JobLaborID = tblJobLaborTech.tblJobLaborTechID)
doesnt seem to preview at all (no value given for parameter)
so i also tried
WHERE (tblJobLabor.JobLaborID = #JLID)
which also doesnt preview.
But that's only the start of the problem. Let's say I can get that part working, how do I get the result of that Scalar query to run for each record in the calling query and return in the dataset as if it were another field in that table?
You don't need to do this using the DB. A datatable can count the records present along a child relation
In your tblJobLabor add another datacolumn (right click, add>>column) and set its Expression property to:
Count(Child(XXX).JobLaborID)
Replace XXX with the name of this DataRelation I've highlighted:
More information can be found by looking at the fairly lengthy documentation on DataColumn.Expression at https://learn.microsoft.com/en-us/dotnet/api/system.data.datacolumn.expression?view=netframework-4.8

How to display out of list items in a combobox?

I have a tbl_ProjectList that includes the project's Name and End Date.
A qry_cboProject queries this table to only display projects in a combobox on Subform A where the End Date is after the selected date on Subform B, both on Mainform C.
On Subform A, a macro copies (INSERT INTO SQL) projects from Subform B's previous months into the new months. However, if an out-of-date project gets copied over to a new month, the combobox field would be empty for that record, even though the Key exists on the back-end.
I've tried playing with the combobox's properties on Subform A by changing the Bound Column, Column Count, Column Widths, and Limit To List, but am only able to get the out-of-date project to display by its Key, rather than its Name.
The front-end reasoning for this macro is that employees do not have to repetitively select the same projects for each month, and employees already working on out-of-date projects may still need to put in some hours to close out the project.
Does anyone have any suggestions? Thank you in advance!
The order in which fields show up in you combo box depends on how the control source is querying the information i.e. to get name and not the key to show up in a combobox using the a control source query like the following:
SELECT Key, Name FROM tbl_ProjectList
You would need to set the following attributes:
Column Count: 2
Column Width: 0"; 2"
Bound Column: 1
It sounds like you may need to requery the control source as well. This should cause all the information to update.
#Parfait - apologies for not describing my problem in more detail. There are multiple subforms on one main form to allow the user to select a date in one subform, which populates projects on a second subform and responsibilities on a third subform.
Jeffrey's suggestion made me realize that the underlying query to the combobox should be adjusted for projects that are carried over into new months, where a foreign key exists in the underlying tbl_ProjectUserEntry
Therefore, I added a WHERE criteria to the query, which uses a DLookUp function to see if the foreign key exists:
DLookUp("[DateID]","tbl_ProjectUserEntry","[DateID] =" & Forms.frm_UserEntry.tbDateID) IS NOT NULL
frm_UserEntry is the main form..
Again, apologies for my brief description to a complex problem.

Are there alternatives to nested LEFT JOIN's in VBA for Microsoft Access?

I am attempting to load a bajillion excel spreadsheets into a single, normalized database. My goal is to duplicate the structure of each original excel spreadsheet but convert the cell entries (the majority of which repeat frequently) into foreign keys before appending to a master table. I've found a process that ALMOST works but I'm running into some problems with an SQL query. I'm fairly savvy in VBA but quite new to databases and SQL, so while I'm confident I can dynamically generate the string necessary for a DoCmd.RunSQL, I'm having trouble with the query structure.
Here's what I'm trying to do:
After importing an excel spreadsheet into an Access table ("tbl_b"), I convert all entries in "tbl_b" to a corresponding foreign key before appending to another, preexisting table ("tbl_A").
For illustrative purposes, say the database contains the following tables:
tbl_a
field1_foreignKeys | field2_foreignKeys
tbl_b
field1_import | field2_import
tbl_field1_primaryKeys
field1_primaryKey | field1
tbl_field2_primaryKeys
field2_primaryKey | field2
I can successfully use the following query to achieve my goal:
INSERT INTO tbl_a (field1_foreignKeys, field2_foreignKeys)
SELECT tbl_field1_primaryKeys.field1_primaryKey, tbl_field2_primaryKeys.field2_primaryKey
FROM (tbl_B LEFT JOIN tbl_field1_primaryKeys ON tbl_b.field1_import = tbl_field1_primaryKeys.field1) LEFT JOIN tbl_field2_primaryKeys ON tbl_B.field2_import = tbl_field2_primaryKeys.field2
This works perfectly for an excel spreadsheet with two columns, but unfortunately, the spreadsheets I'm working with contain 26 columns, each of which must be converted to foreign keys before appending. Access is consistently crashing when I nest more than eight LEFT JOIN's, so I need a different solution. Hopefully this can be done and I'm missing something obvious :p
Any takers?
........................................................................
UPDATE
Regardless of whether or not I'm using the best data structure for my purposes (this database dilettante is optimistic), Don George's suggestion put me on the path to a working solution:
It occurred to me it was unnecessary to preserve "tbl_b" in its original condition, so I looped through each field with a dynamically generated version of the update query below:
UPDATE tbl_b LEFT JOIN tbl_field1_primaryKeys
ON tbl_b.field1_import = tbl_field1_primaryKeys.field1
SET tbl_B.field1_import = tbl_field1_primaryKeys.field1_primaryKey
After updating tbl_b I appended the whole thing to tbl_a all in one go.
Perhaps inelegant, but I thought I'd post my solution in case any other poor soul finds his/herself in an identical situation.

Searching for value in a linked table in power pivot

I have a PowerPivot table that has a column of IDs and a linked table that contains a set of specific IDs that I want to use to create an indicator variable which I can use to sort on in existing tables and charts. Essentially I want:
If the value in column EpisodeID is found anywhere in LostEpisodes[LostID], then return the value "1", otherwise "0".
LostEpisodes is the linked table and LostID is the column that contains the subset of IDs I want to be able to sort on.
I have tried using =IF(VALUES(LostEpisodes[LostID])=[EpisodeID],1,0) but got an error. Is my syntax wrong or should I be using a different approach? Seems simple enough, but I am new to PowerPivot and DAX.
Thanks
OK - So I have found an answer that works and wanted to share. Others may have more elegant solutions, but this worked. This is where I miss MATCH.
I have a linked table called LostEpisodes which contains 2 columns, EpisodeID and Lost (all contain the value of 1 as they are all lost episodes). For my purposes I am manually entering the episode IDs as there are only a few. EpisodeID is also in the main table and is the column I am matching on.
I started with one new column labeled LostLookup with the following formula:
=LOOKUPVALUE(LostEpisodes[Lost],LostEpisodes[EpisodeID],[EpisodeID])
I then created a new column with the following formula:
=if(ISBLANK([LostLookup]),"NotLost","Lost")
This creates the indicator variable I can now use in pivot tables and charts. I have tested it and it works great.
Hope this makes sense!