expression to check if barcode input exists in which case load data for that barcode else continue to create new record - ms-access

Hi I'm using Access 2007 and i am doing a program to enter stock items.
I am using a form and i need to make sure that when the user inputs the barcode of the product the system checks in the table if this exists. If it does exists, i need to load data for this existing item into the 3 additional fields in the same form, otherwise to continue creating the new record.
Now i am trying to use set tempvar in the beforeupdate however i cannot get it right.
any suggestions please.
field name : [barcode]
table to look into is "cartridge static data"
additional fields to fill if barcode exists are : [cartridge] , [end user] , [phone no]
Appreciate any help
regards
Tony

I would insert a combo box using the Access wizzard.
Select the data from "cartridge static data" i.e. [barcode] [cartridge] [end user] [phone no]
Do not hide the first row, and make sure you can see the data width in the wizard as you build it.
When completed go to the combo [data] [row source] and click the three {…}
Check what is displayed ~ for example sort by Barcode, remove nulls etc.
If you have the column widths wrong you can change those in the [format tab].
Column headers default to No which may need changing or you may be happy with that.
Under [other] name check you have a sane name e.g. cbo_barcode_search
Now attach this code to the AfterUpdate property of the Combo Box:
Sub cbo_barcode_search_AfterUpdate ()
Dim rs As DAO.Recordset
If Not IsNull(Me.cbo_barcode_search) Then
'Save before move.
If Me.Dirty Then
Me.Dirty = False
End If
'Search in the clone set.
Set rs = Me.RecordsetClone
rs.FindFirst "[BarCode] = " & Me.cbo_barcode_search
'rs.FindFirst "[BarCode] = """ & Me.cbo_barcode_search & """" 'for text
If rs.NoMatch Then
'Trigger new form or add the just typed data into your form as required
‘e.g. me.field1 = cbo_barcode_search.column(0) ' Barcode
Else
'Display the found record in the form.
' Usually use Me.Bookmark = rs.Bookmark but your question suggests this is not what you want so
'NOTE: First column data is column(0) NOT column(1)
me.field1 = cbo_barcode_search.column(0) ' Barcode
me.field2 = cbo_barcode_search.column(1) ' Cartridge
me.field3 = cbo_barcode_search.column(2) ' end user
me.field4 = cbo_barcode_search.column(3) ' phone no
End If
Set rs = Nothing
End If
End Sub
You will need to modify this to match your field names (eg me.field1 is probably me.barcode but it may be me.str_barcode ~ I don't know what you used.
Hope this gets you on the right track. Paul

Related

Combobox with LimitToList set to false with non-bound field

I have a products table and a tags table with a many-to-many relationship. I also have a pivot table that store the product id and the tag id.
I'd like to be able to show the tag text in the combo box but store the id. This on its own is simple as I can just adjust the column width of the id, however, I'm trying to set LimitToList to No so I can implement some VBA to filter the list when I type in the combo box, but this only appears to be possible if the first column is the bound column, which means the tag id appears in the combo box instead of the text.
How do I show the tag text in the combobox and allow 'LimitToList' to be false?
Leave LimitToList on Yes, and use the NotInList event of the combobox instead.
E.g.
Private Sub cboTag_NotInList(NewData As String, Response As Integer)
Dim RS As Recordset
If MsgBox("Do you want to add '" & NewData & "' as new Tag?", vbYesNo + vbQuestion) _
= vbYes Then
' Add the new tag
Set RS = CurrentDb.OpenRecordset("tbTags")
With RS
.AddNew
!Tag_Text = NewData
.Update
.Close
End With
Response = acDataErrAdded
Else
Response = acDataErrDisplay
' Or a user defined MsgBox and acDataErrContinue
End If
End Sub
(sigh) again I have misunderstood your question. :(
To filter the combobox as the user types a part of a Tag, you use the Change event. This works just fine with LimitToList = Yes.
Private Sub cboTag_Change()
Me.cboTag.RowSource = _
"SELECT Tag_ID, Tag_Text FROM tbTags WHERE Tag_Text LIKE '*" & Me.cboTag.Text & "*'"
' With the instant filtering, it is more convenient for the user
' to always see the filtered dropdown
Me.cboTag.Dropdown
End Sub
Of course at some point the user has to select a Tag from the list. Otherwise there would be no ID to store in the field.
Or if you want him to be able to add new tags, use the code from the other answer. Both events work together as written.
Search-as-you type technique described very good here, including automatic selection of items from opened dropdown combobox after typing few characters.

How can I populate combo box from a database query?

I want to populate a combo box with the results of a query in Access. I'm just not seeing how to do it. As far as I understand, one must first create a record set, read the query results into the record set, then write the record set to the combo box's row source property. Is this correct? is there a simple example somewhere that I can follow? I haven't found one in any of the other threads.
Here's my attempt so far:
Dim RS As Recordset
Dim myDB As Database
Set RS = myDB.OpenRecordset("SourcesNotDisposed", dbOpenDynaset)
Do While Not RS.EOF
With Me.cmbSN
RowSource.AddItem
End With
Loop
With this code, I'm getting an "Object required" error at the RowSource line. cmbSN has data properties:
Row source Type = Table/Query
Bound Column = 0
Limit to List = Yes
Allow value list edits = Yes
Inherit value list = Yes
Show only row source = No
The query only has one visible column called "Serial Number"
Thanks in advance
Thanks for all the suggestions everyone. I've worked it out and found a very simple solution. With the combo box's Row Source Type property set to Table/Query, all I needed to do was set the Row Source property to a valid SQL string. e.g.:
strSQL = "SELECT Sources.[Serial Number] FROM Sources " & _
"WHERE (((Sources.Nuclide)='Cf-252') " & _
"AND ((Sources.[Location / Status])<>'Disposed')) " & _
"ORDER BY Sources.[Serial Number];"
Me.cmbItem.RowSource = strSQL
Me.cmbItem.Requery
Below code insert table fields into combo box. Add this code under onEnter event of combo
Private Sub CM_Enter()
'CM is combobox name
Dim strItem1 As String
Dim strItem2 As String
On Error Resume Next
Dim i As Integer 'Index for loop
With Me.CM
.RowSourceType = "Value List" 'Set rowsource type as Value list
.RowSource = "" 'Clean combo contents
End With
'Loop through field names of table and add them to your combo:
For i = 1 To CurrentDb.TableDefs("table1").Fields.Count - 1
Me.CM.AddItem (CurrentDb.TableDefs("table1").Fields(i - 1).Name)
Next i
'/***Delete unwanted items from the combo
strItem1 = "col1"
strItem2 = "col2"
'CM.RemoveItem strItem1
'CM.RemoveItem strItem2
End Sub
I think you might need to do a 'first read a record' before starting the loop.
Try using a RS.MoveFirst before the Do-While loop?
I think you may also need to do a .MoveNext inside your loop, just before the Loop statement; it's been a long while since I did anything like this in VBA, but it looks to me like it'll just add the same item over and over until it runs out of memory? I don't think the AddItem moves the record pointer to the next record by itself.
You may also need to check what happens if you MoveNext off the end of the record set...
HTH :)

vba function to return record with most recent date. given another criteria

I need to set the default value for a textbox in an ms access 2010 form. The default value needs to be the most recent date in CommunicationTable where the ClientNumber is the same as the ClientNumber associated with the current record in the form. The code below references the correct ClientNumber, but I am not sure how to get the most recent date. I am concerned that DMax might not be the appropriate function for getting the most recent date. How should I change the following to get the most recent date?
=DMax("DateOfCommunication","[CommunicationTable]","[ClientNumber]= "
& [Forms]![Main]![NavigationSubform].[Form]![ClientNumber] & "")
I realize I should also post the larger function in which the above function is nested:
=DLookUp("[Level]","[CommunicationTable]","DateOfCommunication= "
& DMax("DateOfCommunication","[CommunicationTable]","[ClientNumber]= "
& [Forms]![Main]![NavigationSubform].[Form]![ClientNumber] & ""))
Also, the form itself is bound to CommunicationTable. This VBA function is in the DefaultValue dialog box, which I get into via the property sheet for the text box. So I am not sure that creating a sql query will work in this case.
EDIT:
I have uploaded a stripped down copy of the database which reproduces the problem at this file sharing site.
To locate the code:
1.) Open the CommunicationEntryForm and
2.) open the AfterUpdate() event procedure for the ClientNumber field.
Next, to reproduce the problem:
1.) close `CommunicationEntryForm`
2.) In the Main form(which should already be open), click the View tab to open
the most recent CommunicationForm for any Client you want. Note the Level
number for that Communication.
3.) Click on the Communication tab. This will leave the form and show a list
of CommunicationForms for that Client.
4.) Click the Create New Form button. This will open up CommunicationEntryForm.
The value for Level should be the same as the value you noted in step 1 above.
The problem is that this is blank.
Can someone show me how to fix this problem?
#CodeMed - I did download the database but found you have issues other than what you are describing- such as when you 'add' a new communication you simply overwrite an existing record. I managed to get the result you were looking for, but it just changes the 3 records around. Does your non-sample program actually have the ability to create and add new records? As it is, I just changed your existing code to this:
Private Sub cmdNewCommForm_Click()
Dim cNum As Long
Dim strSQL As String
Dim rs As Recordset
Dim db As Database
Set db = CurrentDb
cNum = Forms!Main!NavigationSubform.Form!ClientNumber
strSQL = "SELECT Top 1 Co.Level AS MaxOfLevel " & _
"FROM CommunicationTable co Where Co.ClientNumber = " & cNum
Set rs = db.OpenRecordset(strSQL)
Forms!Main!NavigationSubform.Form!NavigationSubform.SourceObject = "CommunicationEntryForm"
Forms!Main!NavigationSubform.Form!NavigationSubform!ClientNumber = cNum
Forms!Main!NavigationSubform.Form!NavigationSubform!DateOfCommunication = Date
If rs.RecordCount > 0 Then
Forms!Main!NavigationSubform.Form!NavigationSubform!Level = rs!MaxOfLevel
Else
Forms!Main!NavigationSubform.Form!NavigationSubform!Level = 0
End If
Set rs = Nothing
Set db = Nothing
End Sub
What I would do is first grab the date by doing something like:
Dim db as Database
Dim rec as Recordset
Set db = CurrentDB
Set rec = db.OpenRecordset("SELECT Top 1 DateOfCommunication FROM CommunicationTable WHERE ClientNumber= " & [Forms]![Main]![NavigationSubform].[Form]![ClientNumber] & " ORDER BY DateOfCommunication DESC")
This will get the most recent date. Then, in your above VBA, you can just stick rec(0) in where your calculation was:
Me.MyDateField = DLookUp("[Level]","[CommunicationTable]","DateOfCommunication= #" & rec(0) & "#")
Substitute "MyDateField" with whatever that name of your date field actually is.
I'm pretty sure you need the pound signs (or "hashtags" as the kids call them today...) in order for Access to do the calculation on a date value.

how to write a script to look for and correct invalid entries in a table

First off I'd like to make perfectly clear that my knowledge of Access and VBA is extremely limited at best. I have an employee database system that due to it's age has been prone to small data corruption issues and controls breaking due to differences between 2003/2007 and 2010. While I've managed to hash out the bulk of the problems, one that has me especially concered is the script we're using to manage access to the database. The system is split between two files, a frontend where users can access the database and a backend file that contains all of the tables.
The issue I have is in the frontend form that handles the logon for the users. The way the access system is set up is the user enters their SSN, then the script finds their SSN in the table and if it exists looks if an access checkbox is checked. If they have access, they're directed to the main menu, if not they get a denied message. What I've found though is for some reason or another, if an entry in the personnel table has an incomplete SSN, the script breaks and anyone can gain access to the database.
There's a query that runs in the frontend that looks at the master personnel table and pulls just the first two columns, SSAN and Access.
The form itself has a visible text box, "Text8", and a hidden Combo Box "Combo4". Combo4 uses the previously mentioned query for the row source (SELECT qryAccess.SSAN FROM qryAccess;), while Text8 is where the user enters their SSN.
Here's the code right now:
Option Compare Database
Private Sub Combo4_AfterUpdate()
' Find the record that matches the control.
Dim rs As Object
Set rs = Me.Recordset.Clone
rs.FindFirst "[SSAN] = '" & Me![Combo4] & "'"
If Not rs.EOF Then Me.Bookmark = rs.Bookmark
If Me![Access] = True Then
DoCmd.RunMacro "Access"
Else
DoCmd.OpenForm "frmDenied"
End If
End Sub
Private Sub Text8_AfterUpdate()
Me![Combo4] = Me![Text8]
' Find the record that matches the control.
Dim rs As Object
Set rs = Me.Recordset.Clone
rs.FindFirst "[SSAN] = '" & Me![Combo4] & "'"
If Not rs.EOF Then Me.Bookmark = rs.Bookmark
If Me![Access] = True Then
DoCmd.RunMacro "Access"
Else
DoCmd.OpenForm "frmDenied"
End If
End Sub
Like I said before, as long as every entry for the SSNs is a full 9-digits, this system works. However, if for some reason the entry is not the full 9 like I just found in my database (and no, I have no idea what caused that to happen, there is an input mask in place, 000-00-0000;;_), this system breaks. You could type in "abc" for the SSN and gain access to the database.
How can I write a small script that pre-checks the table for SSN entries that don't fit the 9-digit format that is set, and if it finds them, resets them to an unused number, such as 000000000, 000000001, etc?
Also, if you have any suggestions on how to streamline the existing code, I'd be more than happy to take them.
Add this function to you application
Public Function IsValidSSN(ByVal SSN As String) As Boolean
'Determines if SSN is a valid social security number
'requires SSN to be in either "#########" or "###-##-####" format
IsValidSSN = (SSN Like "###-##-####") Or _
SSN Like ("#########")
End Function
Also change your function to this:
Private Sub Combo4_AfterUpdate()
' Find the record that matches the control.
If IsValidSSN(Me![Combo4]) Then
Dim rs As Object
Set rs = Me.Recordset.Clone
rs.FindFirst "[SSAN] = '" & Me![Combo4] & "'"
If Not rs.EOF Then Me.Bookmark = rs.Bookmark
If Me![Access] = True Then
DoCmd.RunMacro "Access"
Else
DoCmd.OpenForm "frmDenied"
End If
Else
DoCmd.OpenForm "frmDenied"
End IF
End Sub
Private Sub Text8_AfterUpdate()
Me![Combo4] = Me![Text8]
If IsValidSSN(Me![Text8]) Then
' Find the record that matches the control.
Dim rs As Object
Set rs = Me.Recordset.Clone
rs.FindFirst "[SSAN] = '" & Me![Combo4] & "'"
If Not rs.EOF Then Me.Bookmark = rs.Bookmark
If Me![Access] = True Then
DoCmd.RunMacro "Access"
Else
DoCmd.OpenForm "frmDenied"
End If
Else
DoCmd.OpenForm "frmDenied"
End If
End Sub
EDIT
Also why are you using a combobox to enter a SSN? You can use input mask on text box. Also I would highly suggest that you convert your system to some other identification other than SSN because it is easily passable to get past this code to look at the table containing everyones SSN, by holding down shift when opening the application. As for streamlining your code just remove that combobox altogether. If they are typing it into a textbox there is no need to put it into a hidden combobox.
You have a text field, SSAN, and with that input mask the dashes are not included in the stored values. So valid values would be 9 digit strings.
If that is correct, you can use a query to identify any invalid stored values.
SELECT y.SSAN, Len(SSAN) AS LenghtOfSSAN
FROM YourTable AS y
WHERE Len(SSAN)<>9 OR y.SSAN ALike '%[!0-9]%';
That query will return rows where SSAN includes < or > 9 characters, and any values which include characters other than digits.
Note the ALike keyword tells the db engine to expect ANSI wild card characters.  If you prefer Access' * wild card instead, change it to Like '*[!0-9]*'
Once you fix the stored values, add a Validation rule for that SSAN field (Like "#########") to require all values consist of 9 digits.
Since it looks like this became more of a "How do I find the user" than "How do I fix the existing entries", let me throw my hat into the ring.
Unless I completely misunderstand this, the existing (and accepted answer) function is HORRIBLE. You can do this all much more efficiently and with less code. First of all, delete Combo4. No need for it. Then do this:
Private Sub Text8_AfterUpdate()
Dim X as Integer
X = DLookup("Access", "qryAccess", "SSAN = '" & Me!Text8 & "'")
If Nz(X) = True Then
DoCmd.RunMacro "Access"
Else
DoCmd.OpenForm "frmDenied"
End If
End Sub
That's all you need. If the user's SSN was stored incorrectly, he's gonna be denied. 7 digits, 8 digits, doesn't make a difference. Only exact matches get through. That is, assuming 0 = False and 1 = True, which should be the default anyway.

"Not a valid bookmark" with DAO Recordset

I'm in the process of converting an Access Data Project (ADP) into a standard ACCDB format with ODBC linked tables. In the ADP, I had overridden the Refresh button to return the user to the current record by using the following code:
Public Sub RibbonCmd_RefreshScreen(ctl As IRibbonControl, ByRef cancelDefault)
On Error GoTo ErrHandler
cancelDefault = False
DoCmd.Echo False
Dim saveBookmark
With Screen.ActiveForm
saveBookmark = .Bookmark
.Requery
.Bookmark = saveBookmark
End With
'Success - cancel the default behavior
cancelDefault = True
ExitHandler:
DoCmd.Echo True
Exit Sub
ErrHandler:
cancelDefault = False
Resume ExitHandler
End Sub
My understanding is that this should work just fine with DAO, but I get error 3159, Not a valid bookmark. I've also tried replacing .Bookmark with .Recordset.Bookmark, but that gave me the same result. Is there something I'm doing wrong here?
Actually, a requery of a form or a requery of a recordset will re-set and invalidate book marks.
So such book marks are no longer valid after a requery.
So the best approach here will depend on either
a) I simply want to re-display any changed records (and not move off current record).
b) I simply want to re-display any changed records AND ALSO display new records (the new records is the critical part).
If you just need a refresh, then you can use the appropriately called command refresh.
Eg:
Me.Refresh
Or in your case
Screen.ActiveForm.Refresh
So the above is ONE line of code and is ALL you need. The current record pointer for the form does NOT change when you use this command. All and any record changed will re-display for you.
Note that since you can behind the form button use:
Me.Refresh
Then LITTLE need is required to call a general routine as you have written.
However, if you need the form to "load" or display any new records added, then you DO have to use requery. In this case as noted book marks in this case all become invalid.
So, for code to requery, then we use the PK value (and hopefully you used the default pk of ID that been the default for 20 years). The code would then become:
Dim lngID As Long
If IsNull(Me!ID) Then Exit Sub
lngID = Me!ID
Me.Requery
Me.Recordset.FindFirst "id = " & lngID
Now of course if the PK id is not the same for each form, then you most certainly could pass the NAME of the PK value to your "general" refresh routine. It would look like:
Public Sub MyRefresh(strPK As String)
Dim lngID As Long
If IsNull(Me(strPK)) Then Exit Sub
lngID = Me(strPK)
Me.Requery
Me.Recordset.FindFirst strPK & " = " & lngID
End Sub
The "hope" here is you actually really JUST need refresh, since as noted this is only one line of code, and better yet it does NOT move the record pointer.
I use VB6 and Visual Data Manager in development. I have had the same problem. Most probably it arose when 2 users tried to update the same record in the same time. So some fields in the table are corrupted.
Here are the steps I used to solve the problem:
1- Copy the structure of the table (lets call it table1)to another table (lets call it table2).
2- Find the correpted record(s) in table1.
3- Transfer the data from table1 to table2 except the corrupted record(s)
4- Reenter the excluded record(s) to table2 again.
5- Rename table1 table3
6- Rename table2 table1
That's all folk
abdobox#yahoo.com
I have used the forms Recordset.AbsolutePosition, and this works fine e.g. in the OnKeyDown exit of a field
Dim PrefilterPosition As Long
Private Sub ValnSubject_KeyDown(KeyCode As Integer, Shift As Integer)
' Not F2 - exit
If KeyCode <> vbKeyF2 Then Exit Sub
' Get the active control
Dim ActiveCtl As Control
Set ActiveCtl = Me.ActiveControl
ActiveControlName = ActiveCtl.Name
' Is the form's filter set?
If Me.Filter = "" Then
' NO: Apply the new filter
' Note the current position in the recordset
PrefilterPosition = Me.Recordset.AbsolutePosition
' Set the filter to the Active control's value
Me.Filter = "[" & ActiveCtl.ControlSource & "]='" & ActiveCtl.Value & "'"
Me.FilterOn = Me.Filter <> ""
Me.Requery
Else
' YES: Clear the filter
Me.Filter = ""
Me.FilterOn = Me.Filter <> ""
Me.Requery
' Align the recordset on the previously stored position
Me.Recordset.AbsolutePosition = PrefilterPosition
End If
' Restore the cursor to where it came from
Me.Controls(ActiveControlName).SetFocus
Ex_it:
End Sub
For context: this code was from an idea for an 'Instant Filter', where you position the cursor on a field in a tab form, press F2, and then a filter is applied so you see only records with the selected field's value. Press F2 again and the filter is removed and the cursor goes back into the place it was when you hit F2 the first time. Bookmarks do not work here, as Albert says above.