Access - Report to show subform results (Join table) - ms-access

I'm a little bit lost with this one. I have a subform, which shows records based on my combobox selection. This is done like this (code is called from Combobox After_Update):
Sub ShowResults1()
With Forms![MYForm].RecordsetClone
.FindFirst "[ID] = " & Forms![MyForm]![CmbSearch]
If Not .NoMatch Then
If Forms![MyForm].Dirty Then Forms![MyForm].Dirty = False
Forms![MyForm].MySubfom.SourceObject = "MySubform"
Forms![MyForm].Bookmark = .Bookmark
End If
End With
End Sub
Main form is bound to a join table, this is It's recordsource (It is linked to 2 tables via ID's in It):
SELECT JoinTable.*, Table1.IDx AS IDx_Table1, Table1.Field1, Table1.Field2, Table1.Field3, Table2.IDy AS IDy_Table2, Table2.Field1, Table2.Field2, Table2.Field3
FROM Table2 INNER JOIN (Table1 INNER JOIN JoinTable ON Table1.IDx = JoinTable.IDx) ON Table2.IDy = JoinTable.IDy;
When upper code is executed, I get a results in subform that matches criteria, so this works fine.
Now, what I want is to have a report, that will show exactly what subform allready shows. Is this too complicated, or is there any simple solution ?
EDIT:
I have created a new query (named "SearchReport"):
SELECT Table2.IDy, Table2.Field1, Table2.Field3
FROM Table2 INNER JOIN (Table1 INNER JOIN Join_Table ON Table1.IDx = JoinTable.IDx) ON Table2.IDy = JoinTable.IDy
WHERE JoinTable.IDy=3;
This query successfully shows records that I want, but only with ID 3. Now I removed "WHERE JoinTable.IDy=3" from Query so that I can show records based on my combobox. This is how I tried opening report:
DoCmd.OpenReport "MyReport", acViewReport, "SearchReport", WhereCondition:="JoinTable.IDy =" & Forms![MyForm]![CmbSearch]
But when Report is opened, Access keeps asking about entering parameter value of IDy. Even If I enter 3, there are all records shown from that query. What Is wrong ??

Both forms and reports have a Record Source property.
In this Record Source property you can specify a table, a query, or a plain SQL statement which is your case.
In VBA, if your Subform is opened and displaying the right information, you can just say MyReport.RecordSource = MySubForm.RecordSource.
But the most proper way to achieve what you want is this :
In the code of your report, add this public sub :
Public Sub Open_This_Report(strSQL)
Me.RecordSource = strSQL
End Sub
In your form, add a button, with this ClickEvent :
Private Sub myButton_Click()
DoCmd.OpenReport "name_of_the_report", acViewNormal
Call Report_name_of_the_report.Open_This_Report(me!SubFormName.Form.RecordSource)
'or
Call Report_name_of_the_report.Open_This_Report("specific SQL query")
End Sub

Solved. I had to select records from Query that I posted in edit (full code for command button_click event - button on form):
Dim sql As String
sql = "SELECT Table2.IDy, Table2.Field1, Table2.Field3" & _
" FROM Table2 INNER JOIN (Table1 INNER JOIN Join_Table ON Table1.IDx =" & _
"JoinTable.IDx) ON Table2.IDy = JoinTable.IDy" & Forms![MyForm]![CmbSearch] DoCmd.OpenReport "APO_IIS", acViewReport
Reports![Myreport].RecordSource = sql

Related

Filtering a MS-Access recordset based on records in another recordset

I have two tables (lets call them Parameters 1 and 2) which both have a many-many relationship with a third table (Options). I need to group the third table records into three groups:
Those exclusively related to [specific Parameter 1 record],
Those exclusively related to [specific Parameter 2 record] and
Those related to both [specific Parameter 1 record] and [specific Parameter
2 record].
I can ignore Option records not related to either of them.
I need to be able to specify which Parameter 1 and 2 records apply in a form (using combo boxes), and have VBA juggle the three lists in the background, updating them as the Option records they contain are "used" elsewhere in the form (with check boxes).
At the risk of asking a bad question I'll submit the code I have - even though it's not a code that fails, just the framework for one that isn't even finished enough to debug yet. I simply haven't got the tools to complete it, as I don't know what methods/properties of what things to use to do it, and can't seem to find the answers in my own research thus far. Comments directing me to other resources will be appreciated, even if you don't have an answer that you're sure is best practice.
Function SetOptions()
If IsNull(cmbParam1) Or IsNull(cmbParam2) Then
MsgBox "You must select both an Param1 and a Param2!", vbCritical, "Wait!"
Exit Function
End If
'Recordsets of allowed Options
Dim Param1Opt, Param2Opt, OverlapOpt
'create recordset of tblOption.Option(s) referenced in qryPr1Opt with Param1 from cmbParam1
Param1Opt = CurrentDb.OpenRecordset("SELECT tblPr1Opt.Option FROM tblPr1Opt " &_
"WHERE Param1 = '" & cmbParam1 & "';")
'create recordset of tblOption.Option(s) referenced in qryPr2Opt with Param2 from cmbParam2
Param2Opt = CurrentDb.OpenRecordset("SELECT tblPr2Opt.Option FROM tblPr2Opt " &_
"WHERE Param2 = '" & cmbParam2 & "';")
'create recordset of tblOption.Option(s) in qryOptOvrlp with Param2 and Param1 from form
OverlapOpt = CurrentDb.OpenRecordset("SELECT qryOptOvrlp.Option FROM qryOptOvrlp " &_
"WHERE Param1 = '" & cmbParam1 & "' AND Param2 = '" & cmbParam2 & "';")
OverlapNum = Param1Num + Param2Num
'Steps remaining:
'1. Get Param1Opt and Param2Opt to only include Options not in overlap
For Each oOpt In OverlapOpt
For Each aOpt In Param1Opt
If aOpt.Value = oOpt.Value Then
'filter this record out of Param1Opt
End If
Next aOpt
For Each gOpt In Param2Opt
If gOpt.Value = oOpt.Value Then
'filter this record out of Param2Opt
End If
Next gOpt
Next oOpt
'2. Get the data in Param1Opt, Param2Opt and OverlapOpt, as well as their
'corresponding Nums to be accessible/editable in other functions/subs
End Function
You can reference the values of controls in SQL statements run in the context of Access, using the following syntax:
Forms!FormName!ControlName
or using square brackets if needed:
Forms![Form Name]!ControlName
Therefore, instead of opening multiple recordsets, you can express each of your points as a single SQL statement with joined tables. You can then either set the RowSource of a combobox or listbox to the statement (if you are only using the statement in one place); or you can save the statement as an Access query, and use the query name as the RowSource (if you need the statement in multiple places).
Given the following schema:
and two comboboxes: cmbParam1 and cmbParam2 on a form named Form1, you can use SQL statements as follows:
1. Records from Options which match tblPr1Opt but have no match in tblPr2Opt
SELECT DISTINCTROW Options.Option
FROM (Options
INNER JOIN tblPr1Opt ON Options.Option = tblPr1Opt.Option)
LEFT JOIN tblPr2Opt ON Options.Option = tblPr2Opt.Option
WHERE tblPr2Opt.Option IS NULL
AND tblPr1Opt.Param1 = Forms!Form1!cmbParam1
Or using the query designer (note the arrow head next to tblPr2Opt; this indicates a left join):
2. Records from Options which match tblPr2Opt but have no match in tblPr1Opt:
SELECT DISTINCTROW Options.Option
FROM (Options
INNER JOIN tblPr2Opt ON Options.Option = tblPr2Opt.Option)
LEFT JOIN tblPr1Opt ON Options.Option = tblPr1Opt.Option
WHERE tblPr1Opt.Option IS NuLL
AND tblPr2Opt.Param2 = Forms!Form1!cmbParam2;
or in the query designer:
3. Records from Options which match on both:
SELECT Options.Option
FROM (Options
INNER JOIN tblPr1Opt ON Options.Option = tblPr1Opt.Option)
INNER JOIN tblPr2Opt ON Options.Option = tblPr2Opt.Option
WHERE tblPr1Opt.Param1 = Forms!Form1!cmbParam1
AND tblPr2Opt.Param2 = Forms!Form1!cmbParam2
Or in the query designer:

Query that populates a datasheet in MS Access, and MsgBox if no values returned

I'm trying to create a query that can run from a button in MS Access. The SQL query I've created is below:
PARAMETERS CASNUMBER Text ( 255 );
SELECT DISTINCT Chemical.Chemical_Name, Hazard.Hazard_Code, Hazard.Hazard_Text
FROM Chemical, Chemical_Hazard, Hazard
WHERE Chemical.Chemical_Id = Chemical_Hazard.Chemical_Id
and Chemical_Hazard.Hazard_Id = Hazard.Hazard_Id
and [CASNUMBER] = Chemical.CAS
;
How do I make it so that a MsgBox appears when there are no values returned?
I'd recommend join tables using JOIN instead of WHERE. Also you can avoid using parameter, which in most cases requres VBA code for query execution. Just create query without parameter, add CAS to columns list:
SELECT DISTINCT Chemical.Chemical_Name
,Hazard.Hazard_Code
,Hazard.Hazard_Text
,Chemical.CAS
FROM (
Chemical_Hazard INNER JOIN Chemical ON Chemical.Chemical_Id = Chemical_Hazard.Chemical_Id
)
INNER JOIN Hazard ON Chemical_Hazard.Hazard_Id = Hazard.Hazard_Id
And then check for CAS in code:
If DCount("*", "MyQuery", "CAS=" & lngCASNumber) = 0 then
MsgBox "CAS not found"
End If

The recordsource [query here] specified on this form or report does not exist

I got error in populating the result of my query to access form but it gives me "The recordsource [query here] specified on this form or report does not exist
Here is my code:
Me.RecordSource = "SELECT Division, Station, EmployeeNumber, BranchCode, AccountNumber, LedgerSetNumber, EmployeeName, EffectDate, TermDate, Amount, BillingType, DateBilled, PolicyNumber, BillingStatus, UpdateStatus, DateUpdated, SequenceNumber FROM DepEdTempBilling WHERE (UpdateStatus<>'Billed') ORDER BY Division, Station, EmployeeNumber, BranchCode, AccountNumber, LedgerSetNumber, EmployeeName"
screenshot:
Your logic is correct. For some reason that doesn't work. I did the same thing with my code. Here it is, hopefully this helps.
Me.RecordSource = "SELECT tblQuoteMaster.[Quote Number], tblQuoteMaster.Status, tblQuoteMaster.Prefix, tblQuoteMaster.[Rev Number], tblQuoteMaster.[AWC Rep], tblQuoteMaster.Estimator, tblQuoteMaster.Customer, CUSLST.Name1 AS Company, tblQuoteMaster.CustomerID, tblQuoteMaster.[Approx Value], tblQuoteMaster.Currency, tblQuoteMaster.Decription, tblQuoteMaster.[Date Received], tblQuoteMaster.[Date Sent], tblQuoteMaster.[Follow Up Date], tblQuoteMaster.[Contact for Quote], tblQuoteMaster.ProductCode FROM (tblQuoteMaster INNER JOIN CUSLST ON tblQuoteMaster.CustomerID = CUSLST.[Account Code]) INNER JOIN tblContact ON CUSLST.[Account Code] = tblContact.[Customer Number] WHERE (" & strSQL & ");"
I have seen some people assign their recordset to the RecordSource. That would always give me your error. For example:
Dim rcd As RecordSet
Set rcd = db.OpenRecordset("SELECT.....")
Me.RecordSource = rcd.Name
Have re-made you table and form and tested, This error occurs when the Property Sheet (Access window not VBA editor) Form/Record Source: has “[query here]” in it clear this line out and try again, if that does not work try a clean new form with this statement. The command itself and SQL appear to be ok.

DLookup Or DMax To Find Value

I am sure this is fairly simple put I am having trouble getting started on this. I use a Form to invoice clients which includes the field [Billing_Month]. What I'm looking to accomplish is this. When I create a new invoice, the [Billing_Month] will look to the last invoice created (use [Invoice_#] with DMax?), and populate the value from that that invoices [Billing_Month]
I have thought to use: Billing_Month = DMax ("Billing_Month", "frmInvoices"), but this doesn't specifically get me the last invoice, it would just look for the highest Billing_Month, which is a text field.
I have thought to use: Billing_Month = DLookup ("Billing_Month", "frmInvoices"), But this doesn't get me the last invoice to pull from.
I'd use a custom function for this - assuming the underlying table is called tblInvoices:
Function GetBillingMonthOfLatestInvoice()
Const SQL = "SELECT TOP 1 Billing_Month FROM tblInvoices ORDER BY [Invoice_#] DESC"
Dim RS AS DAO.Recordset
Set RS = CurrentDb.OpenRecordset(SQL)
If RS.EOF Then
GetBillingMonthOfLatestInvoice = Null
Else
GetBillingMonthOfLatestInvoice = RS(0)
End If
End Function
Update
The above code can be generalised to return other related fields like so:
Function GetValueForLatestInvoice(FieldToLookUp As String)
Dim RS As DAO.Recordset, SQL As String
SQL = "SELECT TOP 1 " + FieldToLookUp + " FROM tblInvoices ORDER BY [Invoice_#] DESC"
Set RS = CurrentDb.OpenRecordset(SQL)
If RS.EOF Then
GetValueForLatestInvoice = Null
Else
GetValueForLatestInvoice = RS(0)
End If
End Function
To use, copy the code to a new standard module, then for each relevant text box on the form, set its Default Value property in the Properties window to something like this:
=GetValueForLatestInvoice("Billing_Month")
That would be for the text box holding the billing month value; for the one holding the billing year, you would use
=GetValueForLatestInvoice("Billing_Year")
You can use a combination of both DLookup() and DMax() like so:
DLookup("Billing_Month","tblInvoices","[Invoice_#]=" & DMax("[Invoice_#]","tblInvoices"))

combobox rowsource based on forms record source (distinct) field

I have a form record source set to a elaborate SQL select statement. That is working fine. If it helps to know, the form layout is Tabular. Here is an example of the data:
order carrier billto employee
1 smgd horm chrnic
2 axxm sele chrnic
3 smgd horm redned
4 mcta cron greand
5 mcta cron greand
Its basically unbilled order entries. I want a combo box to show distinct employee names (chrnic, redned, greand) based on the current records showing. I will be coding it to filter the form. Seems simple, but I am having trouble
Things I have tried:
Tried setting rowsource to me.recordsource, but get an
It appears that I would need to parse & edit that string
I copied the complex query & put as combo box record source & that worked to filter the form, so I know that filter logic is correct. I just want it to be dynamic so we only have to change SQL statement in one place if needed
"I have a form record source set to a elaborate SQL select statement."
Save that query as a named QueryDef. I will pretend you chose qryRecordSource as the name.
"I want a combo box to show distinct employee names ... based on the current records"
For the combo box row source use ...
SELECT DISTINCT employee
FROM qryRecordSource
ORDER BY 1;
And then to filter the form based on the combo selection, add a command button, cmdApplyFilter, and use this in its click event procedure ...
Me.Filter = "[employee] = '" & Me.YourComboName.Value & "'"
Me.FilterOn = True
If the employee names can include an apostrophe, use this for the Filter expression ...
Me.Filter = "[employee] = '" & _
Replace(Me.YourComboName.Value, "'", "''") & "'"
If you want to include a combo row to clear the filter, use a UNION query as the combo row source ...
SELECT "*** ALL ***" AS employee
FROM Dual
UNION
SELECT employee
FROM qryRecordSource
ORDER BY 1;
... where Dual is any table or query which returns just one row. Then in the command button click event you can do ...
If Me.YourComboName.Value = "*** ALL ***" Or _
IsNull(Me.YourComboName.Value) Then
Me.Filter = vbNullString
Me.FilterOn = False
Else
Me.Filter = "[employee] = '" & Me.YourComboName.Value & "'"
Me.FilterOn = True
End If
And actually you wouldn't even need the command button. You could set the Filter from the combo's AfterUpdate event.