How to set custom ID field? - ms-access

I have autonumber field in MS Access.
Here, it's starting with 1, 2, 3,…
But I want to enumerate numbers starts, with
2017ICLAA001, 2017ICLAA002, 2017ICLAA003,…
How to do that?

Simply type "2017ICLAA"000 into the ID field's Format Property

Should be able to figure out what you want with this since "2017...." is not always going to be the same and if you change it then it will jack up your database.
Example of Year-Number output: 17-0001
When the year changes the number auto resets to 1, because it checks the date then the number value which is incremental from 1 to 9,999 each year. You can delete records and it won't affect numbering since it always checks for the largest integer based on the current year, which is defined by your computers time/clock.
Must have the following columns: [AutonumberID] [DateCreated] [ColumnForYear-Number]
You should set the "[DateCreated]" column's "Default Value" in the Table's DesignView to "=Date()" (without quotes) so a date is added automatically when creating a record.
Add the following to your form's [Event Procedure] BEFOREINSERT otherwise if you update content in the record later (BeforeUpdate) it WILL change the record number everytime a change is made. You've been warned!
Do not use the date of a "[Last Modified]" type of column otherwise you will regret it in the future if you change/update anything in the record when the year changes and edits are made (think about it). Ensure you have a dedicated "[DateCreated]" column that doesn't change after inserting/adding the record no matter what year you decide to make any changes.
Here is the code:
Option Compare Database
Private Sub Form_BeforeInsert(Cancel As Integer)
Dim vLast As Variant
Dim iNext As Integer
vLast = DMax("[ColumnForYear-Number]", "[Table]", "[ColumnForYear-Number] LIKE '" & _
Format([txtDateCreated], "yy\*\'"))
If IsNull(vLast) Then
iNext = 1
Else
iNext = Val(Right(vLast, 4)) + 1
End If
Me![ColumnForYear-Number] = Format([txtDateCreated], "yy") & "-" & Format(iNext, "0000")
End Sub
To get more than 9,999 records in one year change the number 4 in Val(Right(vLast, 4)) to a larger integer, then change the zeros in Format(iNext, "0000") to reflect the number of placeholders. The number 4 and there are four zeros. The same thing applies to the year, just change anywhere there is "yy" to "yyyy" for a four digit year. When making changes ensure the data type for the table's field/column can accept the total characters to be calculated or it will chop off any excess characters. Default is usually 255 characters for text however if your's says 8 characters are allowed for the [ColumnForYear-Number] and you are trying to add 9 or more then you will get frustrated troubleshooting a simple problem. Just FYI.
"[txtDateCreated]" is where the actual date entry exists and not the same as "[DateCreated]" which is the column name, unless you named your label that under the "Other" tab in Property Sheet. In other words columns are [columnname] and the textbox area where values are added/changed/viewed in FORMS should be labeled [txtcolumnname] (minus the brackets of course).
Additional options that are already configured into the format you request are listed in the next response (see below).

Since I had some more time on my hands I decided to answer your question more directly with a couple of options. My assumptions are: (1) You want the year 2017 to change automatically and (2) a prefix you define ICLAA followed by (3) an incremental number 001 that resets with each new year and (4) this is for a form with entry boxes (hence [txt...]).
Table Columns Required:
[AutoNumber] <=Not used here, it's just to show it still exists
[Column4UniqueValue] set the data type to Short Text and ensure your columns field size is set to 12 or more otherwise it will not work and will kick an error.
[DateCreated] set to Date/Time with format as General Date default value set =Date(), set Show Date Picker to Never for good measure, and set Locked value to Yes so user cannot change\override the value in the form. Note: this column [DateCreated] is not required if you decide to go with option two (2) listed below.
After you created the columns above in your table go to your form and add the new fields onto the form, click inside the newly added text field box and set its Other name as txt.... , then go into VBA Code Builder [Alt+F11] and add the code from either option one or option two.
Option One (with DateCreated field):
Private Sub Form_BeforeInsert(Cancel As Integer)
Dim Prefix As String
Dim vLast As Variant
Dim iNext As Integer
Prefix = "ICLAA"
vLast = DMax("[Column4UniqueValue]", "[tblSource]", "[Column4UniqueValue] LIKE '" & Format([txtAreaOfDateCreated], "yyyy\*\") & Prefix & "*'")
If IsNull(vLast) Then
iNext = 1
Else
iNext = Val(Right(vLast, 3)) + 1
End If
Me![txtAreaOfColumn4UniqueValue] = Format([txtAreaOfDateCreated], "yyyy") & Prefix & Format(iNext, "000")
End Sub
Option Two (without DateCreated field):
Private Sub Form_BeforeInsert(Cancel As Integer)
Dim Prefix As String
Dim vLast As Variant
Dim iNext As Integer
Prefix = "ICLAA"
vLast = DMax("[Column4UniqueValue]", "[tblSource]", "[Column4UniqueValue] LIKE '" & Format(Date, "yyyy\*\") & Prefix & "*'")
If IsNull(vLast) Then
iNext = 1
Else
iNext = Val(Right(vLast, 3)) + 1
End If
Me![txtAreaOfColumn4UniqueValue] = Format(Date, "yyyy") & Prefix & Format(iNext, "000")
End Sub
Your end results will look exactly like this 2017ICLAA001 and auto increment each year starting from one. Test it by creating a few records then change your computer's date/time clock to a later or earlier year and add another record. It should change with the year and when the year changes it will auto increment to the next highest value for that year. You can test this by toggling the computer year back and forth just to watch the values remain consistent when you add new records.

Related

VBA ACCESS code autoincrementing a value with prefix

I have a table named 'odonto' and it has the fields code (autoincremental), history, surnames and names. I need to generate the code so that it autogenerates the HISTORY obtaining the first letter of the last name which will then have to be concatenated with consecutive numbers for each letter. That is to say that if we have four "FLORES" and a "MENDOZA" in the register it shows in a text box the next samples:
F001
F002
F003
F004
M001
...
Also I need to keep in mind that if a record is deleted it will be replaced by incrementing it again.
I did it and it functions for the asigning value, but it doesn't replace the deleted one if it.
Private Sub APELLIDO_AfterUpdate()
Dim MyStr
MyStr = Left([APELLIDO], 1)
Me.LETRA = MyStr
If IsNull(Me.HISTORIA) Then
Me!HISTORIA = ((MyStr) & "0000" & ([Cant] + 1))
Else
HISTORIA = Me.HISTORIA
End If
Me.Refresh
End Sub
Please your help.

have a number like 000x-000yy that counts the number of invoices issued each month and year so that it resets after each month and year [duplicate]

I have autonumber field in MS Access.
Here, it's starting with 1, 2, 3,…
But I want to enumerate numbers starts, with
2017ICLAA001, 2017ICLAA002, 2017ICLAA003,…
How to do that?
Simply type "2017ICLAA"000 into the ID field's Format Property
Should be able to figure out what you want with this since "2017...." is not always going to be the same and if you change it then it will jack up your database.
Example of Year-Number output: 17-0001
When the year changes the number auto resets to 1, because it checks the date then the number value which is incremental from 1 to 9,999 each year. You can delete records and it won't affect numbering since it always checks for the largest integer based on the current year, which is defined by your computers time/clock.
Must have the following columns: [AutonumberID] [DateCreated] [ColumnForYear-Number]
You should set the "[DateCreated]" column's "Default Value" in the Table's DesignView to "=Date()" (without quotes) so a date is added automatically when creating a record.
Add the following to your form's [Event Procedure] BEFOREINSERT otherwise if you update content in the record later (BeforeUpdate) it WILL change the record number everytime a change is made. You've been warned!
Do not use the date of a "[Last Modified]" type of column otherwise you will regret it in the future if you change/update anything in the record when the year changes and edits are made (think about it). Ensure you have a dedicated "[DateCreated]" column that doesn't change after inserting/adding the record no matter what year you decide to make any changes.
Here is the code:
Option Compare Database
Private Sub Form_BeforeInsert(Cancel As Integer)
Dim vLast As Variant
Dim iNext As Integer
vLast = DMax("[ColumnForYear-Number]", "[Table]", "[ColumnForYear-Number] LIKE '" & _
Format([txtDateCreated], "yy\*\'"))
If IsNull(vLast) Then
iNext = 1
Else
iNext = Val(Right(vLast, 4)) + 1
End If
Me![ColumnForYear-Number] = Format([txtDateCreated], "yy") & "-" & Format(iNext, "0000")
End Sub
To get more than 9,999 records in one year change the number 4 in Val(Right(vLast, 4)) to a larger integer, then change the zeros in Format(iNext, "0000") to reflect the number of placeholders. The number 4 and there are four zeros. The same thing applies to the year, just change anywhere there is "yy" to "yyyy" for a four digit year. When making changes ensure the data type for the table's field/column can accept the total characters to be calculated or it will chop off any excess characters. Default is usually 255 characters for text however if your's says 8 characters are allowed for the [ColumnForYear-Number] and you are trying to add 9 or more then you will get frustrated troubleshooting a simple problem. Just FYI.
"[txtDateCreated]" is where the actual date entry exists and not the same as "[DateCreated]" which is the column name, unless you named your label that under the "Other" tab in Property Sheet. In other words columns are [columnname] and the textbox area where values are added/changed/viewed in FORMS should be labeled [txtcolumnname] (minus the brackets of course).
Additional options that are already configured into the format you request are listed in the next response (see below).
Since I had some more time on my hands I decided to answer your question more directly with a couple of options. My assumptions are: (1) You want the year 2017 to change automatically and (2) a prefix you define ICLAA followed by (3) an incremental number 001 that resets with each new year and (4) this is for a form with entry boxes (hence [txt...]).
Table Columns Required:
[AutoNumber] <=Not used here, it's just to show it still exists
[Column4UniqueValue] set the data type to Short Text and ensure your columns field size is set to 12 or more otherwise it will not work and will kick an error.
[DateCreated] set to Date/Time with format as General Date default value set =Date(), set Show Date Picker to Never for good measure, and set Locked value to Yes so user cannot change\override the value in the form. Note: this column [DateCreated] is not required if you decide to go with option two (2) listed below.
After you created the columns above in your table go to your form and add the new fields onto the form, click inside the newly added text field box and set its Other name as txt.... , then go into VBA Code Builder [Alt+F11] and add the code from either option one or option two.
Option One (with DateCreated field):
Private Sub Form_BeforeInsert(Cancel As Integer)
Dim Prefix As String
Dim vLast As Variant
Dim iNext As Integer
Prefix = "ICLAA"
vLast = DMax("[Column4UniqueValue]", "[tblSource]", "[Column4UniqueValue] LIKE '" & Format([txtAreaOfDateCreated], "yyyy\*\") & Prefix & "*'")
If IsNull(vLast) Then
iNext = 1
Else
iNext = Val(Right(vLast, 3)) + 1
End If
Me![txtAreaOfColumn4UniqueValue] = Format([txtAreaOfDateCreated], "yyyy") & Prefix & Format(iNext, "000")
End Sub
Option Two (without DateCreated field):
Private Sub Form_BeforeInsert(Cancel As Integer)
Dim Prefix As String
Dim vLast As Variant
Dim iNext As Integer
Prefix = "ICLAA"
vLast = DMax("[Column4UniqueValue]", "[tblSource]", "[Column4UniqueValue] LIKE '" & Format(Date, "yyyy\*\") & Prefix & "*'")
If IsNull(vLast) Then
iNext = 1
Else
iNext = Val(Right(vLast, 3)) + 1
End If
Me![txtAreaOfColumn4UniqueValue] = Format(Date, "yyyy") & Prefix & Format(iNext, "000")
End Sub
Your end results will look exactly like this 2017ICLAA001 and auto increment each year starting from one. Test it by creating a few records then change your computer's date/time clock to a later or earlier year and add another record. It should change with the year and when the year changes it will auto increment to the next highest value for that year. You can test this by toggling the computer year back and forth just to watch the values remain consistent when you add new records.

MS Access: Lookup excluding already-selected values; check unique key before record entry complete

I'm currently struggling how to set up validation rules for forms in either Datasheet or Form view that trigger immediately upon going to either another field within the record or to another record entirely.
My form is designed to add records to one destination table where the primary key column needs to match a value of a specific field in any record of a source table. The rest of the fields in the form (and destination table) are for general user input (some DateTime fields, some text, some decimal).
I can get Access to display a standard error dialogue when a user attempts to free-enter a value not on the list immediately after selection of another field or record. The error displayed is
The text you entered isn't an item in the list.
Select an item from the list, or enter text that matches one of the listed items"
And if I reselect a lookup value already selected and go to the next record, I get
The changes you requested to the table were not successful because they would create duplicate values in the index, primary key, or relationship. Change the data in the field or fields that contain duplicate data, remove the index, or redefine the index to permit duplicate entries and try again.
However, I'd like that error (or similar) to appear immediately if going to another field within the same record. In other words, I want it to tell me that it's a duplicate before allowing the user to fill out the rest of the current record in the form or table.
I would like the selection list be restricted to values not previously present in the destination table. Obviously if editing an already-created entry, you should be able to keep the value you had previously (i.e. that value wouldn't be excluded from the dropdown list).
Alternatively there would be a selection dialogue that would appear if an otherwise valid value was duplicated.
Duplicate Value
You've already used that value. Would you like to change this record or the previously-entered record.
⪡ This One ⪢ < Previous >
If "Previous" is selected, it would jump up to the same field in the indicated record, providing a dropdown list for re-selection (and once done would jump back to the "current" record and autoselect the temporarily duplicated value.
I'll edit this post in a bit with my table design details, as well as source setups for the form.
"Solved" this in VBA.
Private Sub MyControl_AfterUpdate()
newval = Me.MyControl.Value
oldval = Me.MyControl.OldValue
If newval = oldval Then Exit Sub ' everything's okay
Dim rs As Object
Set rs = Me.Form.Recordset
whereclause = "MyControl = '" & newval & "'"
qry = "SELECT COUNT(*) as c FROM MyQuery WHERE " & whereclause
qrs = CurrentDb.OpenRecordset(qry)
If qrs.Count = 1 Then cnt = qrs(0).Value
If cnt >= 1 Then
selval = MsgBox("Would you like to keep your selection for this record?" & vbCrLf & "[yes = change previous record's MyField; no = change MyField for this record]", vbYesNo Or VbMsgBoxStyle.vbExclamation Or vbSystemModal Or vbDefaultButton2 Or vbMsgBoxSetForeground, "Duplicate MyField selection encountered")
If selval = vbYes Then
' set focus to the other entry, preserving selection here
thissel = Me.MyControl.ListIndex
Me.MyControl.Value = "temp" ' if a string is okay & so we can jump away from this record
thisloc = Me.Form.CurrentRecord ' record number
rs.Findfirst (whereclause)
thatloc = Me.Form.CurrentRecord
Debug.Print (thisloc & "now ; was" & thatloc)
Me.MyControl.Value = "invalid"
DoCmd.GoToRecord , , acGoTo, thisloc ' jump to the new row
Me.MyControl.Value = newval
DoCmd.GoToRecord , , acGoTo, thatloc ' jump to the one to change
If thissel <= 0 Then thissel = 1 ' may not be useful, given the error handling below
On Error Resume Next
Me.MyControl.ListIndex = thissel - 1
On Error GoTo 0
Me.MyControl.Dropdown
ElseIf selval = vbNo Then
Me.MyControl.Value = Me.MyControl.OldValue
Me.MyControl.Undo ' for some reason this doesn't clear the "dirty" bit, resulting in the edit pencil showing up for the row.
Me.MyControl.SetFocus
End If
Else
Debug.Print ("There were no matches! Das ist gut")
End If
End Sub
Residual Issue(s)
Selecting "Yes" from the dialogue and then hitting escape puts the invalid "invalid" string into the box, which ignores any requirement to restrict the final selection to one in the list (ie Limit to List = 1). Ideally this would "roll back" the two rows.
Maybe I should change this to an OnExit Event so it doesn't trigger before I even leave the cell? Not sure if the primary key violation would happen before this triggers though. OnChange triggers much too frequently (every time you down-arrow through the list).

Allow new record of duplicated cell value if a cell is null

Above is a table that shows what I want to prevent. It allows the entry of a record where the same machine, 1, is related to two contracts at the same time. How do I make a table where I can only insert a new record if all other records with the same idMachine have the cell contracEnded NOT NULL? Thanks for the help.
Assuming you are using a form to enter your data (which you should be) you could try putting the following VBA code in the BeforeUpdate event of the control you are using to enter the data. Here I'm assuming this control is a text box named txtIdMachine, which is bound to the idMachine field in your table (which I'm assuming is named tblMachines).
Private Sub txtIdMachine_BeforeUpdate(Cancel As Integer)
Dim numMachines As Integer, numEnded As Integer
numMachines = DCount("idMachine", "tblMachines", _
"idMachine = " & Me.txtIdMachine)
numEnded = DCount("*", "tblMachines", _
"contractEnded Is Not Null And idMachine = " & Me.txtIdMachine)
If (numMachines - numEnded > 0) Then
Cancel = True
MsgBox "Machine " & Me.txtIdMachine & " is already in use." & _
vbNewLine & "Select a new machine."
End If
End Sub
The DCount(A,B,C) function will return the number of matching entries from field A in a table or query B that matches the search string C (basically the WHERE clause from an SQL query). A,B,C are strings. The "*" tells it to search all columns.
In the end you just have to subtract the number of instances of the machine number the user is trying to enter Me.txtIdMachine from the number of non-Null end dates for that machine, and check to see if there are any idMachine without an end date. Since it's done BeforeUpdate, the current entry doesn't exist yet, so it doesn't count.

Table completely ignoring variable

Private Sub Form_Current()
Dim bytoffcut As Byte
Dim strCriteria
strCriteria = "[WOID] = " & Forms![frmAddStockBooking]![MouldWO]
bytoffcut = Nz(DMax("OffcutNo", "dbo_tblOffcuts", strCriteria), 0) + 1
MsgBox bytoffcut
Me.txtOffcut.Value = bytoffcut
Me.WOID.Value = Forms![frmAddStockBooking]![MouldWO]
Me.txtdate.Value = Now()
End Sub
Can anyone tell me why this is not working? The variable is behaving as expected where bytoffcut increments by one when i create a new record. But when I check the table the field bound to txtOffcut the field reads 1 instead of the incremented value.
EDIT: This code is being used in the On current property of the form. When I create a new record using a button on the form Dmax is used to find the highest offcut No value in a table and add one to it.
This appear to work in the form as the offcut no txtbox increments. But when i look at the table instead of having records with an increasing offcut no Instead all records read 1
Try sending your where clause in the DMax like this, assuming the WOID field in the table is an number type and not text or date.
"[WOID] = " & Forms![frmAddStockBooking]![MouldWO]
It would be better to evaluate your DMax() expression only once, especially if dbo_tblOffcuts is a large linked table without a usable index on [WOID].
If your DMax() expression can return a Null, use Nz() to transform the Null to zero. Then add one.
Dim bytoffcut As Byte
Dim strCriteria
strCriteria = "[WOID] = " & Forms![frmAddStockBooking]![MouldWO]
'Debug.Print strCriteria '
bytoffcut = Nz(DMax("OffcutNo", "dbo_tblOffcuts", _
strCriteria), 0) + 1
MsgBox bytoffcut
Me.txtOffcut.value = bytoffcut
This may not give you what you want when other users are editing dbo_tblOffcuts.
I have managed to solve the issue of multiple records being updated by creating a primary key for the table I am writing to.
I think that because Access could not uniquely identify the record it would edit all the records that met the criteria or something of the ilk. I am not entirely sure myself.