Access SQL "Where" Clause for Textbox on Form - sql

I'm modifying the VBA code developed by someone else and am having difficulty adding a "Where" clause on a form. As I'm a newbie to SQL I appreciate any assistance.
I have a table tbl_FC_Data which contains rows of data which present a forecast of part demand. It has over 43k records. Each record is a forecast for a Part_Number for a Data_Month for a specific company (Company_Code) for a forecast provided on a specific date i.e. Date_of_Forecast. Below is a table with a sample of the data.
Part_Number Data_Month Qty Company_Code Date_of_FC
AN565B8H4 1/1/2020 35 WAL2 12/11/2019
AN565B8H4 2/1/2020 1095 WAL2 12/11/2019
02-14-202-11 12/1/2019 20 D17 12/4/2019
02-14-202-11 1/1/2020 10 D17 12/4/2019
02-14-202-11 5/1/2020 1 D17 12/4/2019
02-14-202-11 6/1/2020 1 D17 12/4/2019
435W2151-49A 7/1/2020 40 API1 6/16/2020
02-14-202-11 6/1/2020 50 EAIL1 6/1/2020
02-14-202-11 7/1/2020 1 EAIL1 6/1/2020
02-14-202-11 1/1/2020 50 CZS1 12/19/2019
02-14-202-11 1/1/2020 50 CZS1 1/30/2020
The Access form contains two list boxes, the first which lists all the companies with data in the table (lstCriteriaCompany) and the second which contains the lists of forecasts dates for all records in the table (lstCriteriaDate_Of_Fc) regardless of company.
The existing VBA/SQL code to list all the forecast dates in the table is:
Me.lstCriteriaDate_Of_Fc.RowSource = "SELECT '#' & Format(D.Date_of_FC,'yyyy-mm-dd') & '#' AS IN_LIST_VALUE, " & _
"Format(D.Date_of_FC,'mm/dd/yyyy') AS DATE_OF_FORECAST " & _
"FROM (SELECT DISTINCT tbl_FC_Data.Date_of_FC FROM tbl_FC_Data) AS D"
It produces the following list of forecast dates:
12/4/2019
12/11/2019
12/19/2019
1/30/2020
6/1/2020
6/16/2020
My goal is that when a user clicks on a company in the first textbox the On Click code (Me.lstCriteriaDate_Of_Fc.RowSource = ...) displays the list of forecasts that relate to the selected company in the first textbox. For example, if CZS1 is selected then the textbox listing the forecasts would be changed to:
12/19/2019
1/30/2020
Here is where I added the Where clause. It returns zero records instead of the two records I expected. When the code is executed a dialog box pops up and asks for the parameter value for D.Company_Code.
Me.lstCriteriaDate_Of_Fc.RowSource = "SELECT '#' & Format(D.Date_of_FC,'yyyy-mm-dd') & '#' AS IN_LIST_VALUE, " & _
"Format(D.Date_of_FC,'mm/dd/yyyy') AS DATE_OF_FORECAST " & _
"FROM (SELECT DISTINCT tbl_FC_Data.Date_of_FC FROM tbl_FC_Data) AS D " & _
"Where D.Company_Code= '" & Me.lstCriteriaCompany.Column(0) & "'"
I also tried HAVING tbl_FC_Data.Company_Code = Me.lstCriteriaCompany.Value but I get a SQL error.
Thanks for any SQL help you can provide.

Referencing listbox selection is rather different from other data controls. Pull required value of selected item by referencing column by its index, even if value is in first column which would be index 0.
Me.lstCriteriaCompany.Column(0)
Concatenate this reference to the SQL string.

I figured out that the Where clause needed to be part of the SELECT DISTINCT clause. Here is the code that works:
Me.lstCriteriaDate_Of_Fc.RowSource = "SELECT '#' & Format(tbl_FC_Data.Date_of_FC,'yyyy-mm-dd') & '#' AS IN_LIST_VALUE, " & _
"Format(tbl_FC_Data.Date_of_FC,'mm/dd/yyyy') AS DATE_OF_FORECAST " & _
"FROM (SELECT DISTINCT tbl_FC_Data.Date_of_FC FROM tbl_FC_Data " & _
"Where tbl_FC_Data.Company_Code = " & Me.lstCriteriaCompany.Column(0) & ");"

Related

How to "roll-up"/aggregate rows from a badly designed table with SQL?

So I'm working with this badly designed table, but it's from another department and I need the data so I have no control over it. How can I get in a proper state? I'm working with MS Access so unfortunately I don't have access to "advanced" SQL functions like partition by, or row_number, etc.
This is the bad table:
KeyID
PA
QL
RuleName
1111
X
YYY
1111
X
ZZZ
1111
X
OOO
I want my final table to look like this:
KeyID
PA
QL
RuleNamePA
RuleNameQL
RuleNameQL2
1111
X
X
YYY
ZZZ
OOO
Any help would be appreciated!
Your desired output is not really a 'proper state' any more than the original data structure is - it's worse. Since the PA and QL fields appear to be Yes/No type and mutually exclusive, a properly normalized table would be like:
ID
KeyID
Cat
RuleName
1
1111
PA
yyy
2
1111
QL
zzz
3
1111
QL
ooo
That structure can be achieved with:
SELECT ID, KeyID, IIf(PA, "PA", "QL") AS Cat, RuleName FROM Table2;
Then that query can be used like a table in subsequent queries such as a CROSSTAB:
TRANSFORM First(RuleName) AS FirstOfRuleName
SELECT KeyID
FROM Query1
GROUP BY KeyID
PIVOT "RuleName" & [Cat] & DCount("*","Query1","Cat='" & [Cat] & "' AND ID<" & [ID])+1;
If there is no unique identifier ID field, change the DCount to:
DCount("*","Query1","Cat='" & [Cat] & "' AND KeyID & Cat & RuleName<'" & [KeyID] & [Cat] & [RuleName] & "'")+1
Here is a version that does not use Query1 and will provide the PA and QL fields which really don't seem necessary. Again, adjust the DCount if there is no ID field.
TRANSFORM First(RuleName) AS FirstOfRuleName
SELECT Table1.KeyID, Max(Abs([PA])) AS P, Max(Abs([QL])) AS Q
FROM Table1
GROUP BY KeyID
PIVOT "RuleName" & IIf([PA],"PA","QL") & DCount("*","Table1","IIf([PA],'PA','QL')='" & IIf([PA],"PA","QL") & "' AND ID<" & [ID])+1;

MS Access Multiple values in parameters

So I am trying to figure out what I am doing wrong, I have a table I am trying to run a query which asks the user if they have a specific district they are looking for....
so my columns are
name district etc
Jay 1
Tom 3
Mary 5
Tim 5
Mike 15
I am trying to be able to have a parameter [which district?:] 1,5 .. It would display
Jay 1
Mary 5
Tim 5
Code:
WHERE
[District] Like "*" & [What District(s)]
& "*" OR [What District(s)] Like "*" & [District] & "*"
but I am getting
Jay 1
Mary 5
Tim 5
Mike 15
I am trying to avoid getting the "15" record.
Consider reversing the LIKE expressions and checking by comma positions for 1) comma after (#,) 2) comma before (,#), or 3) before and after (,#,) and then exact or no comma (=).
SELECT *
FROM Employees
WHERE
[What District(s)] LIKE [District] & ',*'
OR [What District(s)] LIKE '*,' & [District] & ',*'
OR [What District(s)] LIKE '*,' & [District]
OR [Employee ID] = [What District(s)]
Advise user not to include whitespaces between entries as a complexity error strangely raises.
If you are dealing with a list of numbers separated by a quote, you can use the IN operator, like:
""WHERE [District] IN ("" & [What District(s)] & "")""
This would generate a valid SQL expression like:
WHERE [District] IN (1,5)
Reference : the IN operator in ms-access

Update a MS Access table using a formula stored in another table

I have one table called PayerFormulas that includes a different formula for each payer. Another table is PayerData that has the payer and the data we receive. I want to populate PayerData.CheckNum using the appropriate formula stored in PayerFormulas. The CheckNum data in the table below is what I would like the result to be.
In pseudocode it feels like this is what I'm looking for.
Update PayerData PD
inner join PayerFormulas PF on PD.Payer = PF.Payer
set PD.Check = PF.Formula
I've tried the above in a regular Access query and it doesn't work. Trying the following code only puts the formula text in the table, not the result. I've looked at using Eval() in some way, but since my result will often include text, it doesn't look like the route to go down..
Sub testFormula()
Dim SQLString As String
Dim ActiveQuery As QueryDef
SQLString = "Update PayerData PD inner join PayerFormulas PF on PD.Payer = PF.Payer set PD.CheckNum = PF.Formula"
Set ActiveQuery = CurrentDb.CreateQueryDef("", SQLString)
ActiveQuery.Execute dbFailOnError
End Sub
PayerFormulas table
Payer | Formula
-----------|--------
Visa | mid([PayerData].[Data],3,2)
Mastercard | left([PayerData].[Data],2)
Amex | right([PayerData].[Data],2)
PayerData table
Payer | Data | CheckNum
-----------|--------|---------
Visa | 123456 | 34
Visa | ABCDEF | CD
Visa | qwerty | er
Mastercard | 123456 | 12
Mastercard | ABCDEF | AB
Mastercard | qwerty | qw
Amex | 123456 | 56
Amex | ABCDEF | EF
Amex | qwerty | ty
Thank you for any help!
Okay, to continue with the original example of 3 formulas. Your idea to use Eval() is valid but have to concatenate the variable provided by [Data] field. Modify the formulas table to break up the function parts into separate fields.
Payer | Func | Arg1 | Arg2
-----------|---------------------
Visa | mid | 3 | 2
Mastercard | left | 2 |
Amex | right | 2 |
Then in the query that joins tables:
CheckNum: Eval([Func] & "('" & [Data] & "', " & [Arg1] & ", " & [Arg2] & ")")
Note the apostrophe delimiters around [Data].
Or the args can be in one field and entered as comma separated value: 3, 2. Then:
CheckNum: Eval([Func] & "('" & [Data] & "', " & [Args] & ")")
Or, if you really want the formula in one field, enter it as: Mid(PayData,3,2), Left(PayData,2), Right(PayData,2). Then in query calculation, Replace PayData with value of Data field:
CheckNum: Eval(Replace([Formula], "PayData", "'" & [Data] & "'"))
BTW, don't really need to save the result to table, calculate when needed.
Only 3 formulas? Use conditional code in the VBA. Send a card identifier to the procedure as an argument:
Sub testFormulat(strC As String)
Dim result As String
Select Case strC
Case "Visa"
result = Mid(Me.Data, 3, 2)
Case "Mastercard"
result = Left(Me.Data, 2)
Case "AMEX"
result = Right(Me.Data, 2)
End Select
CurrentDb.Execute "Update PayerData set CheckNum = '" & result & "' WHERE ID = " & Me.ID
End Sub
Where will the Data value come from? Is code behind a form? Is form bound to the table result needs to be saved in? If so, the SQL is not needed, simply:
Me!PayerData = result

Lookup with where clause ssrs?

I have a question about a look up function in ssrs. After some research on the forum I managed it to a certain degree. However the last step I can't solve.
In my report I am using two data sets. One set with some costumer parameters and one data set with the turnover grouped by (tip out of this forum) costumer ID and year. With this costumer ID I link the two tables.
=lookup(Fields!cmp_wwn.Value,Fields!cmp_wwn.Value, Fields!Omzet.Value, "Omzet")
When I use the code above I get the first value out of the set. However I want to specify which year I want to show.
With the code below I have tried it again.
=lookup(
Fields!cmp_wwn.Value & "-" & "2015",
Fields!cmp_wwn.Value & "-" & Fields!Datumjaar.Value,
Fields!Omzet.Value, "Omzet")
The warning below appears.
Warning 1 [rsRuntimeErrorInExpression] The Value expression for the textrun ‘Textbox8.Paragraphs[0].TextRuns[0]’ contains an error: Operator '&' is not defined for type 'Guid' and string "-".
Just to give you an idea of the two data sets:
Dataset 1:
SELECT Status, StartDate, Jaar,
Maand, Week, cmp_name, Accountmanager, Classificatie, cmp_fcity, Description, RequestComments, fullname, res_id, cmp_code, target,
cmp_wwn
FROM _VW_ALKLIMAET_MRS_Bezoekverslagen
Dataset 2:
SELECT SUM(bdr_val) AS Omzet, Datumjaar, cmp_wwn
FROM _VW_ALKLIMAET_MRS_omzet
WHERE (Datumjaar > 2013)
GROUP BY Datumjaar, cmp_wwn
Sample data of Dataset 1:
Status Start date Year Month Week Relation name Account manager Realtion classification City fullname ID fullname Costumer code Target Relation ID
Status Startdate Jaar Maand Week cmp_name Accountmanager Classificatie cmp_fcity fullname res_id cmp_code target cmp_wwn
3 12-8-2014 8:00 2014 8 33 van Dorp Hengelo Martijn Moekotte Unknown HENGELO Martijn Moekotte                                                 849             2010935 0 4a3a0504-c255-4e91-b106-0000972bb783
3 4-6-2013 13:30 2013 6 23 Witte Koeltechniek BV Marco van der Haven B Installateur NOORD-SCHARWOUDE Marco van der Haven                                              815              200183 0 cfa97188-c76a-457c-ba78-003d499d86bc
3 6-11-2013 10:00 2013 11 45 Witte Koeltechniek BV Marco van der Haven B Installateur NOORD-SCHARWOUDE Marco van der Haven                                              815              200183 0 cfa97188-c76a-457c-ba78-003d499d86bc
Sample data of Dataset 2:
Turnover DataYear Relation ID Omzet Datumjaar cmp_wwn
-36755,5 2015 f887da07-08ad-4479-84ec-1459be5e3311
-105 2016 ba9e2640-291f-43ee-af5b-559245af165c
-6409 2014 c06cb96c-026a-4274-9db2-89cf9c8ccb2b
-176 2014 70968c94-b3b9-43a0-8b2b-18e62583c75f
You can concatenate two fields in the lookup function.
=lookup(
Fields!cmp_wwn.Value & "-" & "2015",
Fields!cmp_wwn.Value & "-" & Fields!Year.Value,
Fields!Omzet.Value, "Omzet")
It will give you the Omzet value for the customer your row contains and 2015 year. If you want to simplify the expression you can add a calculated field in every dataset and set an expression to concatenate cmp_wwn and year.
=Fields!cmp_wwn.Value & "-" & Fields!Year.Value
Now in your lookup just use the calculated field.
=lookup(
Fields!calculated_field.Value,
Fields!calculated_field.Value,
Fields!Omzet.Value, "Omzet")
UPDATE: GUID field doesn't support & operator
=lookup(
CSTR(Fields!cmp_wwn.Value) & "-" & "2015",
CSTR(Fields!cmp_wwn.Value) & "-" & CSTR(Fields!Datumjaar.Value),
Fields!Omzet.Value, "Omzet")
Let me know if this helps you.

Access Query Match lowest unused number

I have got a query result in MSAccess.
QueryMatch :
InvoiceNumber RegionNumber Group
9448180 73657 A
9448180 74170 A
9448180 74171 A
9448180 78761 A
9448196 73657 A
9448196 74170 A
9448196 74171 A
9448196 78761 A
9448201 73657 A
9448201 74170 A
9448201 74171 A
9448201 78761 A
1234567 12345 B
so on..
Table 2:
RegionNumber InvoiceNumber
73657
74170
74171
78761
The query has a long list , separated by groups.
There can be x + n RegionNumber for x InvoiceNumbers.
n = 0 to 25.
One RegionNumber must be matched with One InvoiceNumber only for each group.
How do we update Table2?
Let us do for smallest RegionNumber to match smallest InvoiceNumber within the Matchresult.
Leaving the last RegionNumber NULL.
Please provide a VBA or can this be done with queries alone ?
Selecting MIN (InvoiceNumber) for each RegionNumber will result in the same InvoiceNumber.
Thanks
Let's consider the following [QueryMatch] sample data
InvoiceNumber RegionNumber Group
123 678 A
234 678 A
345 678 A
123 789 A
We could try to just iterate through the RegionNumber values (ascending) and pick the lowest InvoiceNumber, but that approach will ultimately fail. We would assign InvoiceNumber 123 to RegionNumber 678 and then when it comes time to process RegionNumber 789 the only possible choice would be InvoiceNumber 123 and it has already been taken.
So, we'd better start by getting a list of the RegionNumber values and the number of distinct InvoiceNumbers that each one has. That will let us process the most constrained RegionNumber values first.
SELECT qm.RegionNumber, Count(qm.InvoiceNumber) AS NumDistinctInvoiceNumbers
FROM
(
SELECT DISTINCT RegionNumber, InvoiceNumber FROM QueryMatch
) qm
GROUP BY qm.RegionNumber
ORDER BY 2 ASC
...which returns...
RegionNumber NumDistinctInvoiceNumbers
789 1
678 3
...lets us know that we need to process RegionNumber 789 first, then assign one of the "leftovers" to RegionNumber 678.
Now, to find the lowest unused InvoiceNumber for a given RegionNumber we need to exclude any ones that we have already written to [Table 2]. So, assuming that we have already "given" InvoiceNumber 123 to RegionNumber 789, one way to find a suitable candidate for RegionNumber 678 would be...
DMin("InvoiceNumber", "QueryMatch", "RegionNumber=678 AND InvoiceNumber NOT IN (Select InvoiceNumber FROM [Table 2])")
...which will return the smallest unused InvoiceNumber, or Null if not match is found.
Wrap that up in some VBA code and we get
Public Sub AssignInvoicesToRegions()
Dim cdb As DAO.Database, rstRegion As DAO.Recordset, rst2 As DAO.Recordset
Dim vInvNo As Variant
Set cdb = CurrentDb
Set rst2 = cdb.OpenRecordset("Table 2", dbOpenDynaset)
Set rstRegion = cdb.OpenRecordset( _
"SELECT qm.RegionNumber, Count(qm.InvoiceNumber) AS NumDistinctInvoiceNumbers " & _
"FROM " & _
"( " & _
"SELECT DISTINCT RegionNumber, InvoiceNumber FROM QueryMatch " & _
") qm " & _
"GROUP BY qm.RegionNumber " & _
"ORDER BY 2 ASC", _
dbOpenSnapshot)
Do While Not rstRegion.EOF
Debug.Print rstRegion!RegionNumber
vInvNo = DMin("InvoiceNumber", "QueryMatch", "RegionNumber=" & rstRegion!RegionNumber & " " & _
"AND InvoiceNumber NOT IN (Select Nz(InvoiceNumber, 0) AS InvNo FROM [Table 2])")
If IsNull(vInvNo) Then
MsgBox "No available InvoiceNumber for RegionNumber=" & rstRegion!RegionNumber, _
vbCritical, "Lookup Failed"
Else
rst2.FindFirst "RegionNumber=" & rstRegion!RegionNumber
rst2.Edit
rst2!InvoiceNumber = vInvNo
rst2.Update
End If
rstRegion.MoveNext
Loop
Debug.Print "Done."
rstRegion.Close
Set rstRegion = Nothing
rst2.Close
Set rst2 = Nothing
Set cdb = Nothing
End Sub
Note that in its current form this algorithm is not guaranteed to find a match for every RegionNumber. Depending on the order in which the RegionNumber values are processed some regions may find that all of their candidates have been taken (hence the IsNull() check in the code). In that case you may have to tweak the algorithm to give those regions "first shot" at an InvoiceNumber, possibly by manually assigning a higher priority to those "difficult" regions.