MS Access - How to generate autonumber with sub-autonumber - ms-access

I'm new in MS Access. Currently i need to create a serial number, an autonumber pair with a sub-autonumber. Something like M1-1,M1-2,M1-3,... M2-1,M2-2,M2-3,... M3-1,M3-2,... The number must be unique.
I created a table for Main running number for M1,M2,M3,... create an index to make it unique. Then another table for sub-number, 1,2,3,4,... after that a MainNum foreign key (relationship) and another Index to make it unique.
But the problem is second table i cant figure out a way to make it an autonumber/running number, because it may repeat itself.
Currently out of idea, need some help.

I'd recommend to do not use the serial number as primary/foreign key in tables. Use numeric fields for this: autonumber for primary and number for foreign. It works faster and automatically.
For generating serial number create public function, which can return next value or optionally current one depending on arguments. Current values of first and second part of serial number store in table, lock it when generating new number, it will guarantee unique next number even in multiuser environment. Also you may store all generated numbers in table with composite unique index on both numbers.

Make your PK an autonumber and use that for any relationships. For your serial number use two long integer fields (SN1, SN2). In the before_update event of your form, for new records, call a public function to generate new 'serial numbers'.
Private Sub Form_BeforeUpdate(Cancel As Integer)
Dim lngSN1 AS Long
Dim lngSN2 as Long
If Me.NewRecord Then
'if SN1 is not to be incremented, set it here to whatever you want
If GetSerials(SN1, SN2) Then
Me!SN1 = lngSN1
Me!SN2 = lngSN2
Else
Cancel = True
End If
End If
End Sub
Public Function GetSerials(ByRef SN1 as Long, ByRef SN2 as Long) AS Boolean
If SN1 = 0 Then
SN1 = Nz(DMax("SN1","<yourTable>"), 0) + 1
SN2 = 1
Else
SN2 = DMax("SN2", "<yourtable>","SN1=" & SN1) + 1
End IF
GetSerials = True
End Function
Build a query with a calculated field to create your composite 'SerialNumber'.
SELECT *, "M" & SN1 & "-" & SN2 as SerialNumber FROM <yourtable>
Use that query wherever you want to display the SerialNumber.

Related

Junction between categories

I am making a database for a freelance sign language interpreter. I have a subject table tblClient which holds information regarding the freelancer's clients. There is a lookup table tlkClientClientType showing the various types of clients (categorized on condition -- deaf, deaf/blind, etc). There is also a table called tlkClientModality. In this table are the different types of sign language offered by the interpreter. You can pick the client's preferred modality from the Client table.
Now the tricky part. There are certain modalities (basically just flavors of sign language) that should not be available to pick if the client is a certain type. For example, you cannot use "regular" (visual) sign language with someone who is deaf/blind. This is because regular sign language depends on the person being able to see. Instead, one would use "Tactile ASL" which is a hand-over-hand version of sign language. Basically, I want to limit the modality list based on the client type picked.
To start off my associations, I am making a junction table between the tlkClientClientType and tlkClientModality tables. Here, I will create the correct allowable pairs of client types and modalities. In addition, there is not really a necessary "junction field" to justify this relationship. I am considering making a "dummy field" as a way to still justify such a relationship.
Later, in a form for the client, I will edit the row source query on the modality combo box to be dependent on the choice selected in the client type box. This would be accomplished by checking what records in the junction table match the choice in the client type combo box.
Am I on the right track here? Making a junction table between two lookup tables seems weird. Is there anything wrong with it?
Note -- I would like to stay away from VBA, but I am up to writing macros to accomplish these goals. Any thoughts would be appreciated.
A photo of the relationships is given below.
Relationshipsphoto
Keep your tables in whatever normal form works for your business case. Your choice just changes how the information is stored which means you have to change how you write your queries as the information may be located in a different place. I chose a many to many relationship between client and clienttype.
You want to set the modality combobox contents from the client combobox. This is a problem of the view not the model hence we change the view and not the organization of the data. the key is to set the recordsource of the modality combobox from the afterupdate event of the client combobox.
Showing the results first: if the client is deaf we get:
if the client is blind or blind and deaf we get:
Private Sub cmbClient_AfterUpdate()
Dim RegularASL As Integer: RegularASL = 1
Dim TactileASL As Integer: TactileASL = 2
Dim ClientID As Integer: ClientID = Me.cmbClient
If ClientisBlindandDeaf(ClientID) Then
cmbModality.RowSource = "SELECT * FROM tlkClientModality WHERE ClientModalityID = " & TactileASL
ElseIf isClientBlind(ClientID) Then
cmbModality.RowSource = "SELECT * FROM tlkClientModality WHERE ClientModalityID = " & TactileASL
Else
cmbModality.RowSource = "SELECT * FROM tlkClientModality WHERE ClientModalityID = " & RegularASL
End If
cmbModality.Requery 'reload cmbmodality data
Me.Refresh 'repaint cmbmodality
End Sub
Public Function isClientBlind(ClientID As Integer) As Boolean
'Get rid of * in names vba can't parse the *
Dim isblind: isblind = 2
Dim ClientClientTypeID As Variant 'allows null return type
ClientClientTypeID = DLookup("ClientClientTypeID", "tlkClientClientType", "ClientID = " & ClientID & " AND ClientTypeID = " & isblind)
If IsNull(ClientClientTypeID) Then
isClientBlind = False
Else
isClientBlind = True
End If
End Function
Public Function isClientDeaf(ClientID As Integer) As Boolean
Dim isdeaf: isdeaf = 1
Dim ClientClientTypeID As Variant 'allows null return type
ClientClientTypeID = DLookup("ClientClientTypeID", "tlkClientClientType", "ClientID = " & ClientID & " AND ClientTypeID = " & isdeaf)
If IsNull(ClientClientTypeID) Then
isClientDeaf = False
Else
isClientDeaf = True
End If
End Function
Public Function ClientisBlindandDeaf(ClientID As Integer) As Boolean
If isClientBlind(ClientID) And isClientDeaf(ClientID) Then
ClientisBlindandDeaf = True
Else
ClientisBlindandDeaf = False
End If
End Function
note: cmbModality is set up just like it is bound to the entire tlkModality table then the record source changes are used to filter it in effect.

Filtering Information in A Report Using VBA-Access - Finding the next avaliable null field

I'm trying to organize information in a report in a certain way
I have 9 fields that will be used to store the label for the information
and another 9 fields that store the actual value of the information.
Whenever a field is full, I want it to place the information in the next available field. So that there will be no blank fields in between information.
The issue is that when trying to run this code which triggers two functions, it is not updating the report I referenced to in the two functions, nor is it pulling information from SpecSheetQuery, and I can't figure out why. My guess is that I'm not referencing the information correctly. I also have to figure out how to run this code individually on each record.
Private Sub Detail_Format(Cancel As Integer, FormatCount As Integer)
Servings = DLookup("[servings]", "SpecSheetQuery")
Calories = DLookup("[calories]", "SpecSheetQuery")
If Not IsEmpty(Servings) Then
OpenSlot ("Servings")
OpenFact (Servings)
End If
If Not IsEmpty(Calories) Then
OpenSlot ("Calories")
OpenFact (Calories)
End If
End Sub
OpenSlot function, puts title/label of information into field1 ( which is a field on the report) on the first null/empty field. so that no space is left blank.
Option Compare Database
Option Explicit
Public Function OpenSlot(Slot As String)
Debug.Print Reports!SpecSheet!field1.Value
If Reports!SpecSheet!field1.Value = Null Then
Debug.Print "Slot1"
Slot = Reports!SpecSheet!field1.Value
Debug.Print Reports!SpecSheet!field1.Value
ElseIf Reports!SpecSheet!field2.Value = Null Then
Reports!SpecSheet!field2.Value = Slot
End If
End Function
OpenFact function, puts fact into nut1 ( which is a field on the report) on the first null/empty field. so that no space is left blank.
Public Function OpenFact(fact As String)
If Reports!SpecSheet!nut1.Value = Null Then
Reports!SpecSheet!nut1.Value = fact
Debug.Print Reports!SpecSheet!nut1.Value
ElseIf Reports!SpecSheet!nut2.Value = Null Then
Reports!SpecSheet!nut2.Value = fact
End If
End Function
I'm trying to store this information into this report.
Any help would be greatly appreciated.

Obtain list of occurring field values in report footer - ssrs

I'm trying to obtain a list of the different field values within an SSRS Report, and then display the result set on the page header.
See link below for an example.
I know that usually this would be completed simply with groups but the user does not want the Tasks split out.
Thanks
Example Report:
To get the unique values into a single cell, you will need to utilize the code behind functionality in SSRS.
Click on the background of your report and go to report properties -> Code. Paste this function into the window:
Public Shared Function RemoveDuplicates(ByVal items As Object()) As String()
System.Array.Sort(items)
Dim k As Integer = 0
For i As Integer = 0 To items.Length - 1
If i > 0 AndAlso items(i).Equals(items(i - 1)) Then
Continue For
End If
items(k) = items(i)
k += 1
Next
Dim unique As String = New [String](k - 1) {}
System.Array.Copy(items, 0, unique, 0, k)
Return unique
End Function
In the expression in your table where you want the unique values list, insert this expression:
=Join(Code.RemoveDuplicates(LookupSet(1,1, Fields!ID.Value, "DataSet1")), ",")
"Fields!ID.Value" is a reference to the field in your dataset that you want unique values from.
"DataSet1" is the name of the dataset that your field is located in.
What happens is that at runtime, the entire set of values from your query column are passed to the VB function which uses returns an array of unique values. The expression in the report Joins the unique array values back together with a comma deliminator.

Copy a DataRow to another table (vb.net / mysql)

I have a Two identical data tables in my project, One is Purchase Orders and the other is a template datatable. (IE: the user can select a template when creating a new row in the original table.)
A Save Template button runs:
Public Shared Sub AddPO_as_Template(Name As String, DR As DataRow)
Dim ds As New SomeDataSet
Dim ta As New SomeDataSetDataSetTableAdapters.PurchaseOrderTemplatesTableAdapter
Try
DR("Name") = Name
ds.PurchaseOrderTemplates.ImportRow(DR)
ta.Update(ds)
Catch ex As Exception
CommonRoutines.ShowExceptionDialog("Could not add the Template, an error occured.", ex.Message)
End Try
End Sub
This particular code throws a concurrency violation. I assume this is happening because the ID column is auto increment and I as using the origional row's ID.
Now; the ID in the second table (PurchaseOrderTemplates) is not important at all, so it can be anything. I have tried setting -1, dbnull, "", etc.... the DB keeps trowing exceptions on the update command.
How can I reset the ID column so it just adds as normal? (I know i could create a newrow and move all the columns accross, but this seems the long way.)
Thanks
EDIT: Copying the rows (via .itemarray) works fine, but i need to get the auto increment value from the table somehow to avoid concurrency violations.
Edit2: So i got it working as per the answer below, but I'd still love to know how to get import row working like this.
Adding the Row as follows works.
Public Shared Sub AddPO_as_Template(Name As String, DR As DataRow)
Dim ds As New SomeDataSet
Dim ta As New SomeDataSetTableAdapters.PurchaseOrderTemplatesTableAdapter
Dim NewRow As DataRow
NewRow = ds.PurchaseOrderTemplates.NewRow
NewRow.ItemArray = DR.ItemArray
NewRow("Name") = Name
NewRow("ID") = 1
ds.PurchaseOrderTemplates.Rows.Add(NewRow)
ta.Update(ds)
End Sub
The MySQL database ignores the value in the ID column, and just sets its own auto increment value.

Convert values from Access Combo Box to string

I need to convert the values from combo box to a string so I can add that string to a variable, to a function to eventually add to a database.
Here is my sub that grabs text from my form and from the combo box:
Private Sub cbRowStudentGrade_Change()
Course_ID.SetFocus
rowCourseID = Course_ID.Text
StuRed_ID.SetFocus
rowStudentRedID = StuRed_ID.Text
cbRowStudentGrade.SetFocus
cbRowStudentGrade = cbRowStudentGrade.Column(0)
CurrentDb.Execute "qryInputGrades"
MsgBox (rowCourseID)
MsgBox (rowStudentRedID)
MsgBox (cbRowStudentGrade)
Requery
Repaint
End Sub
And here are the functions that I am using as criteria in my Access query builder.
Public Function funcRowCourseID() As String
funcRowCourseID = rowCourseID
End Function
Public Function funcRowStudentRedID() As String
funcRowStudentRedID = rowStudentRedID
End Function
Public Function funcCbRowStudentGrade() As String
funcCbRowStudentGrade = cbRowStudentGrade
End Function
My query:
INSERT INTO tblRegistrationGrade ( Red_ID, Course_ID, Grade )
VALUES (funcRowStudentRedID(), funcRowCourseID(), funcCbRowStudentGrade());
I think there is a datatype mismatch between the database and what the combobox value actually is. But, if there were a datatype mismatch wouldn't there be an error stating as such? My database requires short text, which these are.
You're doing this way too complicated.
You can directly refer from your INSERT query to the form controls:
INSERT INTO tblRegistrationGrade ( Red_ID, Course_ID, Grade )
VALUES (Forms!myForm!StuRed_ID, Forms!myForm!Course_ID, Forms!myForm!cbRowStudentGrade);
and get rid of almost all of the code, except calling the query.
As John wrote, it would be better placed in cbRowStudentGrade_AfterUpdate().
Or, instead of the INSERT query, use a DAO.Recordset with AddNew, see:
How to: Add a Record to a DAO Recordset
There you can also directly use the values from your from controls without worrying about data types.