Add autoincrement to existing query (not table) in MS Access 2016 - ms-access

I have query in MS ACCESS 2016 that I need to add autonumber to. Basically, the query output results in one column of data and I want to add a new column to this output with numbers starting from 1 to whatever the row count of the query output will be. I dont want to create a new table from my query output though. Is there a way to do this in a query? I managed to add a new ID column that just has a scalar value, however what I need is auto increment here. Any thoughts?
SELECT qry.ColA, 1 AS ID
FROM qry;

Yes, use the RowNumber function from my article:
Sequential Rows in Microsoft Access
Full code at GitHub: VBA.RowNumbers
' Builds consecutive row numbers in a select, append, or create query
' with the option of a initial automatic reset.
' Optionally, a grouping key can be passed to reset the row count
' for every group key.
'
' Usage (typical select query):
' SELECT RowNumber(CStr([ID])) AS RowID, *
' FROM SomeTable
' WHERE (RowNumber(CStr([ID])) <> RowNumber("","",True));
'
' Usage (with group key):
' SELECT RowNumber(CStr([ID]), CStr[GroupID])) AS RowID, *
' FROM SomeTable
' WHERE (RowNumber(CStr([ID])) <> RowNumber("","",True));
'
' The Where statement resets the counter when the query is run
' and is needed for browsing a select query.
'
' Usage (typical append query, manual reset):
' 1. Reset counter manually:
' Call RowNumber(vbNullString, True)
' 2. Run query:
' INSERT INTO TempTable ( [RowID] )
' SELECT RowNumber(CStr([ID])) AS RowID, *
' FROM SomeTable;
'
' Usage (typical append query, automatic reset):
' INSERT INTO TempTable ( [RowID] )
' SELECT RowNumber(CStr([ID])) AS RowID, *
' FROM SomeTable
' WHERE (RowNumber("","",True)=0);
'
' 2018-08-23. Gustav Brock, Cactus Data ApS, CPH.
'
Public Function RowNumber( _
ByVal Key As String, _
Optional ByVal GroupKey As String, _
Optional ByVal Reset As Boolean) _
As Long
' Uncommon character string to assemble GroupKey and Key as a compound key.
Const KeySeparator As String = "¤§¤"
' Expected error codes to accept.
Const CannotAddKey As Long = 457
Const CannotRemoveKey As Long = 5
Static Keys As New Collection
Static GroupKeys As New Collection
Dim Count As Long
Dim CompoundKey As String
On Error GoTo Err_RowNumber
If Reset = True Then
' Erase the collection of keys and group key counts.
Set Keys = Nothing
Set GroupKeys = Nothing
Else
' Create a compound key to uniquely identify GroupKey and its Key.
' Note: If GroupKey is not used, only one element will be added.
CompoundKey = GroupKey & KeySeparator & Key
Count = Keys(CompoundKey)
If Count = 0 Then
' This record has not been enumerated.
'
' Will either fail if the group key is new, leaving Count as zero,
' or retrieve the count of already enumerated records with this group key.
Count = GroupKeys(GroupKey) + 1
If Count > 0 Then
' The group key has been recorded.
' Remove it to allow it to be recreated holding the new count.
GroupKeys.Remove (GroupKey)
Else
' This record is the first having this group key.
' Thus, the count is 1.
Count = 1
End If
' (Re)create the group key item with the value of the count of keys.
GroupKeys.Add Count, GroupKey
End If
' Add the key and its enumeration.
' This will be:
' Using no group key: Relative to the full recordset.
' Using a group key: Relative to the group key.
' Will fail if the key already has been created.
Keys.Add Count, CompoundKey
End If
' Return the key value as this is the row counter.
RowNumber = Count
Exit_RowNumber:
Exit Function
Err_RowNumber:
Select Case Err
Case CannotAddKey
' Key is present, thus cannot be added again.
Resume Next
Case CannotRemoveKey
' GroupKey is not present, thus cannot be removed.
Resume Next
Case Else
' Some other error. Ignore.
Resume Exit_RowNumber
End Select
End Function

Related

How Do I make it so that the row number resets whenever a certain field changes in a MS Access qry?

I’m using this code and I’m trying to get it so that the row number resets whenever a certain field changes in a qry. I have the below to functions and then I use it in the qry. I export the query to use elsewhere.
Any Ideas and or samples?
For example, if field A is orange, orange, orange, banana, apple, apple, grapefruit.
Then I’m looking to have this in field B: 001, 002, 003, 001, 001, 002, 001
This is what I need | This is what I get
Field A Field B | Field A Field B
orange 001 | orange 1
orange 002 | orange 2
orange 003 | orange 3
banana 001 | banana 4
apple 001 | apple 5
apple 002 | apple 6
grapefruit 001 | grapefruit 7
Option Compare Database
Private lngRowNumber As Long
Public Function RowNumber(UniqueKeyVariant As Variant) As Long
lngRowNumber = lngRowNumber + 1
RowNumber = lngRowNumber
End Function
Public Function ResetRowNumber() As Boolean
lngRowNumber = 0
ResetRowNumber = True
End Function
Query
SELECT
TBL_Test.RowID,
TBL_Test.Cust_Number,
TBL_Test.Loan_Number,
RowNumber(TBL_Test.RowID) AS RowNum
FROM TBL_Test
WHERE (((ResetRowNumber())<>False))
ORDER BY TBL_Test.Cust_Number, TBL_Test.Loan_Number;
First, you miss is a unique ID, then an expanded function that takes a group key.
So, add an AutoNumber field to table as the first step.
Next, at my project VBA.RowNumbers you can find my function RowNumber which has the option for a group key:
' Builds consecutive row numbers in a select, append, or create query
' with the option of a initial automatic reset.
' Optionally, a grouping key can be passed to reset the row count
' for every group key.
'
' Usage (typical select query having an ID with an index):
' SELECT RowNumber(CStr([ID])) AS RowID, *
' FROM SomeTable
' WHERE (RowNumber(CStr([ID])) <> RowNumber("","",True));
'
' Usage (typical select query having an ID without an index):
' SELECT RowNumber(CStr([ID])) AS RowID, *
' FROM SomeTable
' WHERE (RowNumber("","",True)=0);
'
' Usage (with group key):
' SELECT RowNumber(CStr([ID]), CStr[GroupID])) AS RowID, *
' FROM SomeTable
' WHERE (RowNumber(CStr([ID])) <> RowNumber("","",True));
'
' The Where statement resets the counter when the query is run
' and is needed for browsing a select query.
'
' Usage (typical append query, manual reset):
' 1. Reset counter manually:
' Call RowNumber(vbNullString, True)
' 2. Run query:
' INSERT INTO TempTable ( [RowID] )
' SELECT RowNumber(CStr([ID])) AS RowID, *
' FROM SomeTable;
'
' Usage (typical append query, automatic reset):
' INSERT INTO TempTable ( [RowID] )
' SELECT RowNumber(CStr([ID])) AS RowID, *
' FROM SomeTable
' WHERE (RowNumber("","",True)=0);
'
' 2020-05-29. Gustav Brock, Cactus Data ApS, CPH.
'
Public Function RowNumber( _
ByVal Key As String, _
Optional ByVal GroupKey As String, _
Optional ByVal Reset As Boolean) _
As Long
' Uncommon character string to assemble GroupKey and Key as a compound key.
Const KeySeparator As String = "¤§¤"
' Expected error codes to accept.
Const CannotAddKey As Long = 457
Const CannotRemoveKey As Long = 5
Static Keys As New Collection
Static GroupKeys As New Collection
Dim Count As Long
Dim CompoundKey As String
On Error GoTo Err_RowNumber
If Reset = True Then
' Erase the collection of keys and group key counts.
Set Keys = Nothing
Set GroupKeys = Nothing
Else
' Create a compound key to uniquely identify GroupKey and its Key.
' Note: If GroupKey is not used, only one element will be added.
CompoundKey = GroupKey & KeySeparator & Key
Count = Keys(CompoundKey)
If Count = 0 Then
' This record has not been enumerated.
'
' Will either fail if the group key is new, leaving Count as zero,
' or retrieve the count of already enumerated records with this group key.
Count = GroupKeys(GroupKey) + 1
If Count > 0 Then
' The group key has been recorded.
' Remove it to allow it to be recreated holding the new count.
GroupKeys.Remove (GroupKey)
Else
' This record is the first having this group key.
' Thus, the count is 1.
Count = 1
End If
' (Re)create the group key item with the value of the count of keys.
GroupKeys.Add Count, GroupKey
End If
' Add the key and its enumeration.
' This will be:
' Using no group key: Relative to the full recordset.
' Using a group key: Relative to the group key.
' Will fail if the key already has been created.
Keys.Add Count, CompoundKey
End If
' Return the key value as this is the row counter.
RowNumber = Count
Exit_RowNumber:
Exit Function
Err_RowNumber:
Select Case Err
Case CannotAddKey
' Key is present, thus cannot be added again.
Resume Next
Case CannotRemoveKey
' GroupKey is not present, thus cannot be removed.
Resume Next
Case Else
' Some other error. Ignore.
Resume Exit_RowNumber
End Select
End Function
Then you can build this query:
SELECT
Fruit.[Field A],
Format(RowNumber(CStr([Id]),[Field A]),"000") AS [Field B]
FROM
Fruit
WHERE
RowNumber(CStr([Id]))<>RowNumber("","",True);
which will output:

Renumbering sequence numbers

I would like to add a auto sequential number under STOP # field. I have fields as Route, Direction, Stop #, & location. So for example M1 going North has 10 stops (1-10) and vice versa for South bound.
You can use the RowNumber function from my article:
Sequential Rows in Microsoft Access
' Builds consecutive row numbers in a select, append, or create query
' with the option of a initial automatic reset.
' Optionally, a grouping key can be passed to reset the row count
' for every group key.
'
' 2018-08-23. Gustav Brock, Cactus Data ApS, CPH.
'
Public Function RowNumber( _
ByVal Key As String, _
Optional ByVal GroupKey As String, _
Optional ByVal Reset As Boolean) _
As Long
' Uncommon character string to assemble GroupKey and Key as a compound key.
Const KeySeparator As String = "¤§¤"
' Expected error codes to accept.
Const CannotAddKey As Long = 457
Const CannotRemoveKey As Long = 5
Static Keys As New Collection
Static GroupKeys As New Collection
Dim Count As Long
Dim CompoundKey As String
On Error GoTo Err_RowNumber
If Reset = True Then
' Erase the collection of keys and group key counts.
Set Keys = Nothing
Set GroupKeys = Nothing
Else
' Create a compound key to uniquely identify GroupKey and its Key.
' Note: If GroupKey is not used, only one element will be added.
CompoundKey = GroupKey & KeySeparator & Key
Count = Keys(CompoundKey)
If Count = 0 Then
' This record has not been enumerated.
'
' Will either fail if the group key is new, leaving Count as zero,
' or retrieve the count of already enumerated records with this group key.
Count = GroupKeys(GroupKey) + 1
If Count > 0 Then
' The group key has been recorded.
' Remove it to allow it to be recreated holding the new count.
GroupKeys.Remove (GroupKey)
Else
' This record is the first having this group key.
' Thus, the count is 1.
Count = 1
End If
' (Re)create the group key item with the value of the count of keys.
GroupKeys.Add Count, GroupKey
End If
' Add the key and its enumeration.
' This will be:
' Using no group key: Relative to the full recordset.
' Using a group key: Relative to the group key.
' Will fail if the key already has been created.
Keys.Add Count, CompoundKey
End If
' Return the key value as this is the row counter.
RowNumber = Count
Exit_RowNumber:
Exit Function
Err_RowNumber:
Select Case Err
Case CannotAddKey
' Key is present, thus cannot be added again.
Resume Next
Case CannotRemoveKey
' GroupKey is not present, thus cannot be removed.
Resume Next
Case Else
' Some other error. Ignore.
Resume Exit_RowNumber
End Select
End Function

How do I fix random numbers after they've been generated in access?

I have generated unique pseudorandom numbers for each row which are subject to a particular field (Field1) in a query in Access. They have been successfully generated and I would like to fix them (kind of like copy and pasting as values). I guess my question would be, is this the best way to do this or will they always change as they are being recalculated on the query? I am open to any other suggestions, but once they have been calculated for the first time, I want them to stay as they are and not change again. Thanks!
Here is the current query's SQL:
SELECT [qry_1].*, Rnd([Field1]) AS Random
FROM qry_1;
You don't need a table. You can use a collection:
' Builds random row numbers in a select, append, or create query
' with the option of a initial automatic reset.
'
' Usage (typical select query with random ordering):
' SELECT RandomRowNumber(CStr([ID])) AS RandomRowID, *
' FROM SomeTable
' WHERE (RandomRowNumber(CStr([ID])) <> RandomRowNumber("",True))
' ORDER BY RandomRowNumber(CStr([ID]));
'
' The Where statement shuffles the sequence when the query is run.
'
' Usage (typical select query for a form with random ordering):
' SELECT RandomRowNumber(CStr([ID])) AS RandomRowID, *
' FROM SomeTable
' ORDER BY RandomRowNumber(CStr([ID]));
'
' The RandomRowID values will resist reordering and refiltering of the form.
' The sequence can be shuffled at will from, for example, a button click:
'
' Private Sub ResetRandomButton_Click()
' RandomRowNumber vbNullString, True
' Me.Requery
' End Sub
'
' and erased each time the form is closed:
'
' Private Sub Form_Close()
' RandomRowNumber vbNullString, True
' End Sub
'
' Usage (typical append query, manual reset):
' 1. Reset random counter manually:
' Call RandomRowNumber(vbNullString, True)
' 2. Run query:
' INSERT INTO TempTable ( [RandomRowID] )
' SELECT RandomRowNumber(CStr([ID])) AS RandomRowID, *
' FROM SomeTable;
'
' Usage (typical append query, automatic reset):
' INSERT INTO TempTable ( [RandomRowID] )
' SELECT RandomRowNumber(CStr([ID])) AS RandomRowID, *
' FROM SomeTable
' WHERE (RandomRowNumber("",True)=0);
'
' 2018-09-11. Gustav Brock, Cactus Data ApS, CPH.
'
Public Function RandomRowNumber( _
ByVal Key As String, _
Optional Reset As Boolean) _
As Single
' Error codes.
' This key is already associated with an element of this collection.
Const KeyIsInUse As Long = 457
Static Keys As New Collection
On Error GoTo Err_RandomRowNumber
If Reset = True Then
Set Keys = Nothing
Else
Keys.Add Rnd(-Timer * Keys.Count), Key
End If
RandomRowNumber = Keys(Key)
Exit_RandomRowNumber:
Exit Function
Err_RandomRowNumber:
Select Case Err
Case KeyIsInUse
' Key is present.
Resume Next
Case Else
' Some other error.
Resume Exit_RandomRowNumber
End Select
End Function
It is explained in detail in my article Random Rows in Microsoft Access
(If you have no account, browse to the link: Read the full article).
Full code including a demo is on GitHub: VBA.RowNumbers

MS Access Update Query based on Index Number and other Criteria

I have a function I am trying to do for a database I am working on for my job. I'm not the most proficient with Access so I apologize if I am not wording this in the best way.
What I am trying to do is create a query/macro that will mimic the behavior as shown
and result into this:
The logic is as follows
1) for each record - take the LEN of the string in StdName. Take that number of characters and UPDATE that to the Name field. The remaining characters after the LEN is moved to the 'SuffixString' Field
2)for each record - count the number of occurrences of the string in the 'StdName' field for any records ON OR BEFORE the index number and UPDATE the 'Name' field with whatever is in there already and concatenate with "_n" where n is the occurence
example: index 1 - has one occurrence of 'Car1' in the StdName Field between record 1 and record 1. index 1 'Name' is changed to Car1_1
example: index 2 - has two occurrences of 'Car1' in the StdName Field between record 1 and record 2. index 2 'Name' is changed to Car1_2
example: index 6 - has one occurrence of 'Car3" in the StdName Field between record 1 and record 6. index 6 'Name' is changed to Car3_1
Can something like this be done with an access query? I've never developed in Access before and my boss really wants to see this function kept inside access instead of being moved in an out of excel.
(I have step 1 setup this way to later put in logic where StdName does not match Name. example: "Car1_1" for Name and StdName "Car2". I realize I could just Concatenate StdName with the function in step 2 in this example i described, but I have a real world purpose of doing it this way)
This will be done on an MDB format
Thank you
You can use my RowCounter function:
SELECT RowCounter(CStr([Index]),False,[StdName])) AS RowID, *
FROM YourTable
WHERE (RowCounter(CStr([Index]),False) <> RowCounter("",True));
or:
SELECT [StdName] & "_" & CStr(RowCounter(CStr([Index]),False,[StdName]))) AS RankedName, *
FROM YourTable
WHERE (RowCounter(CStr([Index]),False) <> RowCounter("",True));
Edit - to update:
UPDATE s_before
SET [Name] = [StdName] & "_" & CStr(RowCounter(CStr([Index]),False,[StdName]))
WHERE (RowCounter(CStr([Index]),False) <> RowCounter("",True));
Code:
Public Function RowCounter( _
ByVal strKey As String, _
ByVal booReset As Boolean, _
Optional ByVal strGroupKey As String) _
As Long
' Builds consecutive RowIDs in select, append or create query
' with the possibility of automatic reset.
' Optionally a grouping key can be passed to reset the row count
' for every group key.
'
' Usage (typical select query):
' SELECT RowCounter(CStr([ID]),False) AS RowID, *
' FROM tblSomeTable
' WHERE (RowCounter(CStr([ID]),False) <> RowCounter("",True));
'
' Usage (with group key):
' SELECT RowCounter(CStr([ID]),False,CStr[GroupID])) AS RowID, *
' FROM tblSomeTable
' WHERE (RowCounter(CStr([ID]),False) <> RowCounter("",True));
'
' The Where statement resets the counter when the query is run
' and is needed for browsing a select query.
'
' Usage (typical append query, manual reset):
' 1. Reset counter manually:
' Call RowCounter(vbNullString, False)
' 2. Run query:
' INSERT INTO tblTemp ( RowID )
' SELECT RowCounter(CStr([ID]),False) AS RowID, *
' FROM tblSomeTable;
'
' Usage (typical append query, automatic reset):
' INSERT INTO tblTemp ( RowID )
' SELECT RowCounter(CStr([ID]),False) AS RowID, *
' FROM tblSomeTable
' WHERE (RowCounter("",True)=0);
'
' 2002-04-13. Cactus Data ApS. CPH
' 2002-09-09. Str() sometimes fails. Replaced with CStr().
' 2005-10-21. Str(col.Count + 1) reduced to col.Count + 1.
' 2008-02-27. Optional group parameter added.
' 2010-08-04. Corrected that group key missed first row in group.
Static col As New Collection
Static strGroup As String
On Error GoTo Err_RowCounter
If booReset = True Then
Set col = Nothing
ElseIf strGroup <> strGroupKey Then
Set col = Nothing
strGroup = strGroupKey
col.Add 1, strKey
Else
col.Add col.Count + 1, strKey
End If
RowCounter = col(strKey)
Exit_RowCounter:
Exit Function
Err_RowCounter:
Select Case Err
Case 457
' Key is present.
Resume Next
Case Else
' Some other error.
Resume Exit_RowCounter
End Select
End Function

Random number using Date() in Expression Builder

I want to generate random number using Date() to format it like for example: ddmmyyyyHhNnSs
How do I achieve that? Is that even possible?
I was kinda hoping I can do it easy way by the expression builder but I seem to fail on each approach ;)
This number need to populate txtID field and it will be unique identifier for each database entry.
That's quite easy - with a twist.
Problem is that Rnd only returns a Single and the resolution of this only allows for 10000000 unique values. As you request a resolution to the second and with 86400 seconds per day, that only leaves a span of 115.74 days while the range of Date spans 3615899 days:
TotalDays = -CLng(#1/1/100#) + CLng(#12/31/9999#)
To overcome this, use Rnd twice which will result in 1E+15 possible values or 11574074074 days - way beyond what's needed:
RandomDouble = Rnd * Rnd
Now, to limit the possible values to fit into the range of data type Date, just follow the documentation:
RandomValue = (UpperValue - LowerValue) * Rnd + LowerValue
and apply the date values:
RandomDouble = (CLng(#12/31/9999#) - CLng(#1/1/100#)) * Rnd * Rnd + CLng(#1/1/100#)
This, however, will result in values containing unwanted milliseconds, thus perform the proper conversion to Date value using CDate which will round to the nearest second, and you have the final expression:
RandomDate = CDate((CLng(#12/31/9999#) - CLng(#1/1/100#)) * Rnd * Rnd + CLng(#1/1/100#))
Use the value as is if your field is of datatype Date or - if text - apply a format to this with Format(RandomDate, "yyyymmddhhnnss") and a sample output will be:
01770317032120
01390126010945
50140322081227
35290813165627
09330527072433
20560513105943
61810505124235
09381019130230
17010527033132
08310306233911
If you want numeric values, use CDec to convert (CLng will fail because of overflow):
RandomNumber = CDec(Format(RandomDate, "yyyymmddhhnnss"))
All said, I'm with #Bohemian - if you just want a unique timestamp and have less than one transaction per second, just use data type Date for your field and use Now:
TimeStamp = Now()
and apply a format to this of yyyymmddhhnnss.
However, Multiplying random numbers together alters the
probablility distribution:
Uniform Product Distribution
Thus, a better method is to create a random date, then a random time, and possibly a random count of milliseconds - I wrote above, that CDate rounds a value to the nearest second; it doesn't, only whenever Access displays a date/time with milliseconds the displayed valued is rounded to the second.
So I modified the function to take care of this:
Public Function DateRandom( _
Optional ByVal UpperDate As Date = #12/31/9999#, _
Optional ByVal LowerDate As Date = #1/1/100#, _
Optional ByVal DatePart As Boolean = True, _
Optional ByVal TimePart As Boolean = True, _
Optional ByVal MilliSecondPart As Boolean = False) _
As Date
' Generates a random date/time - optionally within the range of LowerDate and/or UpperDate.
' Optionally, return value can be set to include date and/or time and/or milliseconds.
'
' 2015-08-28. Gustav Brock, Cactus Data ApS, CPH.
' 2015-08-29. Modified for uniform distribution as suggested by Stuart McLachlan by
' combining a random date and a random time.
' 2015-08-30. Modified to return selectable and rounded value parts for
' Date, Time, and Milliseconds.
' 2015-08-31. An initial call of Randomize it included to prevent identical sequences.
Const SecondsPerDay As Long = 60& * 60& * 24&
Dim DateValue As Date
Dim TimeValue As Date
Dim MSecValue As Date
' Shuffle the start position of the sequence of Rnd.
Randomize
' If all parts are deselected, select date and time.
If Not DatePart And Not TimePart And Not MilliSecondPart = True Then
DatePart = True
TimePart = True
End If
If DatePart = True Then
' Remove time parts from UpperDate and LowerDate as well from the result value.
' Add 1 to include LowerDate as a possible return value.
DateValue = CDate(Int((Int(UpperDate) - Int(LowerDate) + 1) * Rnd) + Int(LowerDate))
End If
If TimePart = True Then
' Calculate a time value rounded to the second.
TimeValue = CDate(Int(SecondsPerDay * Rnd) / SecondsPerDay)
End If
If MilliSecondPart = True Then
' Calculate a millisecond value rounded to the millisecond.
MSecValue = CDate(Int(1000 * Rnd) / 1000 / SecondsPerDay)
End If
DateRandom = DateValue + TimeValue + MSecValue
End Function
Format now() and cast to a long:
select CLng(format(now(), 'ddmmyyyyhhnnss')) as txnId
Although this is not "random", it is unique as long as there are never more than one transaction per second (confirmed in comment above).