Find Lowest Value in Columns Access 2010 - ms-access

I have a table in Access 2010 that has 3 separate priority fields. I have a sub that looks through the columns, finds the smallest number, and puts it in an Overall Priority field.
Ex.
SubProjNo | GOPri | StrPri | SOPri
--------+-----------+----------+------------------
1234-12-01 | 100 | 7 | 61
1234-12-02 | | 18 | 2
1234-12-03 | 51 | |
ProjNo: 1234-12-00 Overall_Priority:2
I originally had the code under Private Sub Form_Current() but it slowed the program down way too much, so I moved it to an AfterUpdate for the subform that the table is in.
Private Sub MFWorkProjectssubform_AfterUpdate()
Dim MinGOPri As Variant
Dim MinStrPri As Variant
Dim MinSOPri As Variant
MinGOPri = DMin("[GOPri]", "[WorkProjects]", "WorkProjects.PROJNO = Activity.PROJNO")
MinStrPri = DMin("[StrPri]", "[WorkProjects]", "WorkProjects.PROJNO = Activity.PROJNO")
MinSOPri = DMin("[SOPri]", "[WorkProjects]", "WorkProjects.PROJNO = Activity.PROJNO")
Overall_Priority = IIf(((IIf([MinGOPri] < [MinStrPri], [MinGOPri], [MinStrPri])))
< [MinSOPri], ((IIf([MinGOPri] < [MinStrPri], [MinGOPri], [MinStrPri]))), [MinSOPri])
End Sub
The problem is, now, all the columns are cleared and only the largest value is left. Any suggestions for how to get this to work, or how to speed it up if I put it back in Form_Current would be really appreciated.

You don't need all this. For the Overall_Priority textbox use this expression as ControlSource:
=IIf(((IIf([GOPri]<[StrPri],[GOPri],[StrPri])))<[SOPri],((IIf([GOPri]<[StrPri],[GOPri],[StrPri]))),[SOPri])
Edit for Null and reduced:
=IIf(IIf(Nz([GOPri],9999)<Nz([StrPri],9999),Nz([GOPri],9999),Nz([StrPri],9999))<Nz([SOPri],9999),IIf(Nz([GOPri],9999)<Nz([StrPri],9999),Nz([GOPri],9999),Nz([StrPri],9999)),Nz([SOPri],9999))
Use this as a fourth column; name it, say, RowMin.
Then, in the footer, use =Min([RowMin]) as the controlsource for your totals box.

How about using recordsets, is this an option ?
Dim rst As Object
Dim minValue As Integer
Dim fieldCounter As Long
Dim minPriority as Long
minPriority = 9999
Set rst = Me.recordsetclone
With rst
.MoveFirst
While Not .EOF
For fieldCounter = 0 To .Fields.Count-1
if(.Fields(fieldcounter).name = "GOPri" or .Fields(fieldcounter).name = "StrPri" or .Fields(fieldcounter).name = "SOPri" ) then
Debug.print "Now you are checking : " &.Fields(fieldcounter).Name & " with value : " & .Fields(fieldcounter) & " Current minPriority = " & minPriority
If len(Nz(.Fields(fieldCounter),"")) > 0 Then
If .Fields(fieldCounter) < minPriority Then minPriority = .Fields(fieldCounter)
End If
End if
Next
.MoveNext
Wend
End With
Set rst = Nothing
Overall_Priority = minPriority
Maybe you need to adjust the fieldCounter to match your Table structure
The fields are counted from 0 -->.... according to your question.
Fields(0) = SubProjNo
Field(1) = GoPRi

If you want this column to always be a function of the other three fields, then you could create a calculated field to the table. The help documents can show you how; also this article gives directions:
https://support.office.com/en-us/article/Add-a-calculated-field-to-a-table-14a60733-2580-48c2-b402-6de54fafbde3
Generally you would define a new field on the table and set it's formula to the maximum of the other three fields. Then any time the calculated field is referenced it will always give you the maximum of them.
The other option is to just not worry about saving the field at all at the time of data entry and simply create a view that adds a field defined to be the maximum of the three values.

Related

Form with multiple subforms - synchronize record change of subforms

I have a form (F_ptselect) with multiple subforms (F_s1, F_s2, F_s3). On the main form I have a combo box that allows me to choose an integer identifier (i.e., ID = 1001, id = 1002, id = 1003, id = 1004, etc.). The subforms are also all linked by ID using "Link Master Fields" and "Link Child Fields". I've found and modified vba that allows me to choose an ID (say 1001) from the combo box on F_ptselect, and subsequently pull up all the data for ID = 1001 on F_s1, F_s2, and F_s3.
Here's that vba:
Private Sub find_ID_AfterUpdate()
' Find the record that matches the control.
Dim rs As Object
Set rs = Me.Recordset.Clone
rs.FindFirst "[ID] = " & Me![find_ID] & ""
If Not rs.EOF Then Me.Bookmark = rs.Bookmark
End Sub
Now, for each ID there are multiple records (i.e., ID=1001 and day=1, ID=1001 and day=2, ID=1002 and day=1, ID=1002 and day=2 etc.). I'd like to be able to have a combo box or button or something that allows me to synchronize the ability to cycle through these records of a single ID. So if I select ID 1001 from the F_ptselect combo box, I'd like to see F_s1, F_s2, and F_s3 for ID 1001, day 1. Then I'd like to be able to change to day 2 for ID 1001 quickly using a combo box selection, button or something. Currently, I'd have to go to the record arrows at the bottom of each subform to change the record. Each row of data has a primary key (let's call it KEY) as well. So a query row or table row would look like:
KEY
ID
Day
1
1001
1
2
1001
2
3
1002
1
4
1002
2
Options:
RecordsetClone/Bookmark method for each subform
applied by Gustav sample Access db in https://www.experts-exchange.com/articles/18107/Synchronizing-Multiple-Subforms-in-Access.html?preview=cUa6D5QxDFA%3D
set each subform Filter and FilterOn properties
parameterized query as RecordSource for each subform
I always name subform container different from the form it holds, like ctrFS1. For option 2, consider:
Sub cbxDay_AfterUpdate()
Dim strF As String
With Me
strF = "[Day]=" & .cbxDay
.ctrFS1.Form.Filter = strF
.ctrFS1.Form.FilterOn = True
.ctrFS2.Form.Filter = strF
.ctrFS2.Form.FilterOn = True
.ctrFS3.Form.Filter = strF
.ctrFS3.Form.FilterOn = True
End With
End Sub
If you name each subform container like: ctrFS1, ctrFS2, ctrFS3, consider:
Dim x As Integer
With Me
For x = 1 to 3
.Controls("ctrFS" & x).Form.Filter = "Day=" & .cbxDay
.Controls("ctrFS" & x).Form.FilterOn = True
Next
End With
Here's the final code (based on the answer from June7) for any interested. The "Day" field is actually a string in my tables so that's why the concatenation syntax is for a string.
Private Sub find_day_AfterUpdate()
Dim strF1 As String
With Me
strF1 = "[Day]='" & .find_day & "'"
.F_s1.Form.Filter = strF1
.F_s1.Form.FilterOn = True
End With
Dim strF2 As String
With Me
strF2 = "[Day]='" & .find_day & "'"
.F_s2.Form.Filter = strF2
.F_s2.Form.FilterOn = True
End With
Dim strF3 As String
With Me
strF3 = "[Day]='" & .find_day & "'"
.F_s3.Form.Filter = strF3
.F_s3.Form.FilterOn = True
End With
End Sub

MS ACCESS: Code to validate data in table

Below I have some code I've written to validate whether the user entered data on a form, which populates a table. I am trying to confirm whether they have left field (MinAge) null. I am getting a data mismatch when I run the code. Is this the best way to do this? Help!
Dim MinAgeVal As Integer
MinAgeVal = DLookup("[MinAge]", "User_ProductDefaultsAge")
If MinAgeVal Is Null Then
x = MsgBox("Missing Minimum Age Value", vbCritical)
Else
x = MsgBox("clear", vbCritical)
End If
Also, the may be multiple rows within the table.
(UPDATED):
Ok... I have a table, which is populated by a user from a form. The user will enter a series of age ranges (min and max)... 0 - 5, 6 - 10, etc... each min / max range will be on its own row... I need to write code that will check each row for three things... 1) that there aren't any fields (min or max) that are null... 2) that the min range is not greater or equal to the max range... the the next row of data is in sequential order (max year of record 1 is less than the min year of record 2)
Min Year Max Year
0 1
2 10
15
Below, some code was provided for guidance...
Dim RS As DAO.Recordset
Dim SQL As String
'ordering is only important if you want the FIRST three MIDs.
'If you don't care, just omit the "order by MID" part.
SQL = "select top 3 MID from DealContent where DealID = xxx order by MID"
Set RS = CurrentDb.OpenRecordset(SQL)
Do While Not RS.EOF
Me!MID = Me!MID & RS("mid") & " "
RS.MoveNext
Loop
RS.Close
Set RS = Nothing
I get what most of the code is doing but can't figure out how to make/alter my code to do:
Set RS = CurrentDb.OpenRecordset(SQL)
Do While Not RS.EOF
Me!MID = Me!MID & RS("mid") & " "
RS.MoveNext
Try this:
Dim MinAgeVal As Variant
MinAgeVal = DLookup("[MinAge]", "User_ProductDefaultsAge")
If IsNull(MinAgeVal) Then
x = MsgBox("Missing Minimum Age Value", vbCritical)
Else
x = MsgBox("clear", vbCritical)
End If
The answer that Gustav provided will only work for one row. Dlookup cannot handle more than one record. You will need to use a recordset. Please see the link

MS Access VBA - Recordset SQL Not returning correct amount

I have VBA code that queries a table. The Query view in MS Access returns the correct results, however the vba returns a different result.
Table called tbl_ADMIN_CLASS_INFO
Client_ID | POLICY_GROUP
12345a | 1
12345a | 2
12345a | 2
12345a | 2
12345a | 2
Column Definitions from Table:
CLIENT_ID = Text
POLICY_GROUP = Number
VBA
Public Sub NextPageControl()
Dim dbs As Database
Dim rst As Recordset
Dim CurrentTableName As String
Dim CurrentFormName As String
Dim NextPageSQL As String
Dim CurrentPage As Form
Dim LastRecord As Integer
Dim Nextpage As Integer
Dim TestPolicy As Long
Dim TestClient As String
TestPolicy = Forms!frm_ADMIN_CLASS_INFO.POLICY_GROUP 'Stepping Through Code shows 12345a
TestClient = Forms!frm_ADMIN_CLASS_INFO.CLIENT_ID 'Stepping Through Code shows 2
CurrentTableName = Screen.ActiveForm.RecordSource
CurrentFormName = Screen.ActiveForm.Name
Set CurrentPage = Screen.ActiveForm
Set dbs = CurrentDb
NextPageSQL = "SELECT * FROM " & CurrentTableName & " WHERE ((POLICY_GROUP = " & TestPolicy & ") AND (CLIENT_ID = '" & TestClient & "'))"
Debug.Print NextPageSQL
Set rst = CurrentDb.OpenRecordset(NextPageSQL, dbOpenDynaset)
MsgBox rst.RecordCount
...More Stuff
The problem is that this VBA returns 5 for rst.RecordCount when it should return 4....
Firstly, the following instruction is not optimal as it can fool you if you're in the case where your form's record source is a SQL query and not a table:
CurrentTableName = Screen.ActiveForm.RecordSource
So make sure that this instruction retruns the correct table name.
Secondly: using recordset.recordcount might not return the expected results depending on your cursor type and the datasource. From microsoft:
The cursor type of the Recordset object affects whether the number of
records can be determined. The RecordCount property will return -1 for
a forward-only cursor; the actual count for a static or keyset cursor;
and either -1 or the actual count for a dynamic cursor, depending on
the data source.
So to be sure you're always returning the correct amount of records, do a :
rst.movelast
prior to do the recordcount
Your code should work fine after those corrections.

Type mismatch error when comparing listboxes

Dim lastcomp As String
Dim qty As Integer
Dim rs As New ADODB.Recordset
rs.Open "select Prem1Item,Prem1Qty from [TU FAR Before VB] order by Prem1Item", accCon
Do While Not rs.EOF
If Not IsNull(rs(0).Value) Then
If rs(0).Value <> "n/a" Then
If rs(0).Value <> "" Then
premlist.AddItem rs(0).Value & Format(rs(1).Value, "00")
End If
End If
End If
rs.MoveNext
Loop
rs.Close
Dim i As Integer
Dim j As Integer
i = 1
For i = 1 To premlist.ListCount
For j = 1 To finallist.ListCount
**If Not finallist(j) = premlist(i) Or finallist(j) = "" Then**
finallist.AddItem premlist(i)
End If
Next j
Next i
AccessConnection ("Close")
End If
I am trying to take the records and pull all of the items in Prem1Item and condense then down to not show duplicates and also get the amount from Prem1Qty and show the total of each item it finds. I was trying to put them in these listboxs and then export them to a table that has 2 columns (Premium and Sum)
I am getting error 13 Type mismatch highlighting the area I have put in Bold ("If Not finalist(j) = premlist(i) Or finalist(j) = "" Then"). My plans were to get that list populated and then fill the table to generate my report with.
A list box object does not allow you to retrieve row values with an index value, like you would for an array, or a VBA Collection, or a recordset Fields collection, and so on.
There is probably a better way to say that, but I don't know how. But attempts such as the following will throw that "Type Mismatch" error ...
Debug.Print Me.finallist(1)
Debug.Print TypeName(Me.finallist(1))
If you want to retrieve the bound column value from each of the list box's rows, use the ItemData property.
Dim i As Long
For i = 0 To (Me.finallist.ListCount - 1)
Debug.Print Me.finallist.ItemData(i)
Next
Debug.Print "done"
I think you should try adding the .value to your comparrison e.g.
finallist(j).value = premlist(i).value

How to evaluate text of a Field Name in Access VBA

I'm looking to iterate through a set of fields as part of a table that follow a specific format. The table contains N pairs of these fields (Var_1, Value_1, Var_2, Value_2, etc).
I need to iterate through these fields and extract the data to write it out to a text file. I'd like to use a loop, I'd rather not hardcode each field into my VBA as the fields will likely grow in time and not every field will be populated for every record. I guess if there was a way to "evaluate" a field when its name is dynamically created in a string, that would solve my problem.
So, for example...
For i = 1 to FieldCount
' Write data to each field
Initially I thought of something like this
For i=1 to FieldCount
myStr = "!Var_"+CStr(i) + " = " + "!Value_" + CStr(i)
WriteLine(myStr)
but course, it prints the text literally... any way to get Access to evaluate that text first?
Perhaps there is a better way to approach this entirely?
You can use your record set's Fields collection, and refer to the value of any individual field by referencing the field's name.
rs.Fields("field_name").Value
You can generally drop the explicit .Value since that's the field's default property.
Public Sub printFieldPairs()
Dim strSql As String
Dim db As DAO.Database
Dim rs As DAO.Recordset
Dim N As Long
strSql = "SELECT * FROM tblJoeS;"
Set db = CurrentDb
Set rs = db.OpenRecordset(strSql)
With rs
Do While Not .EOF
For N = 1 To 3
Debug.Print .Fields("Var_" & N) & " = " & _
.Fields("Value_" & N)
Next N
.MoveNext
Loop
End With
rs.Close
Set rs = Nothing
Set db = Nothing
End Sub
That's what I think you're asking for. However, if the number of field pairs grows, you will have to revise the table structure. So my inclination would be to use a different table structure.
row_identifier fKey fValue
1 Var_1 foo
1 Var_2 bar
1 Var_3 baz
2 Var_1 abcd
As suggested improvement to HansUp answer:
....
Dim fld as DAO.Field
For Each fld in rs.fields
debug.? fld.value
Next fld