Running Dlookup() on a query with row count column as criteria (MS access) - sql

Im trying to run Dlookup to return all values of a column in a query's results. As Dlookup can only return 1 result I have added a row count column to the query so I can use the row count as the criteria for the Dlookup.
My query results look like this in the results
Query design view
Query results 2
In SQL view the query is as follows:
SELECT tblAssets.SerialNumber, tblAssets.ID, tblAssets.AssetType, tblPlacing.Location, tblPlacing.PlacingStartDate, tblPlacing.PlacingEndDate, RowNumber([ID]) AS [NO]
FROM tblAssets INNER JOIN (tblLocations RIGHT JOIN tblPlacing ON tblLocations.LocationID = tblPlacing.Location) ON tblAssets.ID = tblPlacing.AssetID
GROUP BY tblAssets.SerialNumber, tblAssets.ID, tblAssets.AssetType, tblPlacing.Location, tblPlacing.PlacingStartDate, tblPlacing.PlacingEndDate, RowNumber([ID])
HAVING (((tblAssets.AssetType)=55) AND ((tblPlacing.Location)=[Forms]![FrmPPM]![TXTLocationID]) AND ((tblPlacing.PlacingEndDate) Is Null) AND ((ResetRowNumber())<>False));
I have added the row count with the following video (https://www.youtube.com/watch?v=HWbpzETe-M0), let me know if more information about this is needed.
The query results look to be correct, however, when using the Dlookup (beneath) it returns null.
Dim VAR1 as Variant
VAR1 = DLookup("[SerialNumber]", "QRYPPM", "[NO] = 1")
When I try and return the [NO] column value it works.
VAR1 = DLookup("[NO]", "QRYPPM", "[SerialNumber] = '6501038'")

I don't have your data, so can't run a full test, but I ran something similar using my RowNumber function (below), and DLookup was able to filter on the returned rownumber (your [NO]) and return a value from another field.
So, try to use this function (your SQL will need minor adjustments, see in-line comments, please):
' 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
The full story can be found in my project VBA.RowNumbers.

Related

SQL Server: create an incremental counter for records in the same year?

I have a table with the following columns:
EmployeeID
EventDate (mm/dd/yyyy)
Event
I need to create a new column which would count each event by year and insert a value in the format ##-yyyy. For example, I want to create a file like Counter:
EmployeeID EventDate Event Counter
------------------------------------------
001 01/05/2018 A 01-2018
002 12/12/2018 A 01-2018
001 03/01/2019 A 01-2019
001 04/05/2019 A 02-2019
002 05/05/2019 A 01-2018
I don't need to count by the event or event type. I just need to include a counter for each event in a year and to increment for each event by the date that it happened. So an event in January 2019 would have a lower number than an event in June 2019.
If this was SQL server:
SELECT
...,
CONCAT(
FORMAT(
ROW_NUMBER() OVER(PARTITION BY employeeid, YEAR(eventdate) ORDER BY eventdate ASC),
'D2'
),
'-',
YEAR(eventdate)
) as counter
FROM ...
ROW_NUMBER() will increment a counter from 1, that restarts every different employee/year. We format this to have a leading 0, then append a hyphen and the year
If you want all events in the same month to have the same number, consider a DENSE_RANK() OVER(PARTITION BY employeeid, YEAR(eventdate) ORDER BY MONTH(eventdate)) instead of a row number.
With a few differences from the answer of #Caius Jard which is almost correct.
SELECT
EmployeeID,
EventDate,
[Event],
FORMAT(ROW_NUMBER() OVER(PARTITION BY DATEPART(YEAR, EventDate), EmployeeID, [Event] ORDER BY EventDate ASC) , 'D2')
+ '-'
+ FORMAT(DATEPART(YEAR, EventDate), 'D4') AS Counter
FROM YOUR_TABLE
In Access, you will need a custom function like my RowNumber that allows for grouping:
' 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
Then your query could be:
SELECT
EmployeeID,
EventDate,
Event,
RowNumber(CStr([EventDate]),[EmployeeID] & "-" & CStr(Year([EventDate]))) AS RowCount,
Format([RowCount],"00-") & CStr(Year([EventDate])) AS EventCount
FROM
Events
WHERE
RowNumber(CStr([EventDate]),[EmployeeID] & "-" & CStr(Year([EventDate])))<>RowNumber("","",True)
ORDER BY
EventDate;
and the result would be:
Full code can be found on GitHub: VBA.RowNumbers

Count results of query in variable

I’ve converted a txt file to access.
Say my access query would have
Data.Employeeid, Data.Location, Data.Hours, Location.Percent, Location.Union, Data.Date
Now the query on this dataset would return duplicates. To process the data further I’d like the data.date field to count up (by one for every duplicate).
I could figure this out with a variable.
Would someone know how I can let the same select query count the number of duplicates (based on employeeid)?
Basically there are 3 joins in that query, which is what gives me a hard time here.
You can use my RowNumber function which allows for grouping:
' 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
It is documented in full in my article:
Sequential Rows in Microsoft Access
Also, a demo is included to download.
No login is required; just locate the link: Click to read the full article.

How do I reset numbering in tables?

I have some data that I have been working with. With that, I have been deleting records on-the-fly. Now that I have a working data model, I want to re-start my auto-numbering. How do I reset my existing data to adhere to an auto-formatting starting from 1....n?
I have tried to do a Compact and Repair but that didn't seem to fix the issue.
For reference, my table looks like this:
R-002
R-054
R-123
R-057
R-061
I would like to get them back to:
R-001
R-002
R-003
R-004
R-005
And for each subsequent entry added, adhere to this new auto-numbering so the next record, for example, will be R-006.
Writing an UPDATE query works for immediate fixing but it doesn't address the adherence to the auto-numbering for future entries.
I would think there is an elegant way to do this. The data in my tables are part of Relationships so it makes it a little tricky.
If anyone has any tips / recommendations, I would appreciate it.
What you need is sequential numbering of the records.
I wrote an article on the various methods for doing this:
Sequential Rows in Microsoft Access
One is to add row numbers:
' 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
These you could format as you like, for example:
RNumber: "R-" & Format([RwoNumber], "000")

How to add sequenced number based on sorted value in query in Access

I have a query which returns some values (att1). I would like also to have next to it the values which would represent a sorted order of att1. Something like this:
att1 att2
19 3
2 2
46 4
78 5
1 1
What would be the solution or the right approach to do this?
Assuming a table name of table1, The following should yield the desired result:
select a.att1, (select count(*) from table1 b where b.att1 <= a.att1) as att2
from table1 a;
For every record, the query calculates the number of records less than or equal to the current record, which is then output as the sort index.
I wrote an article on the various methods for this:
Sequential Rows in Microsoft Access
In its simplest form:
SELECT RowNumber(CStr([ID])) AS RowID, *, FROM SomeTable;
using the RowNumber function:
' 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
All code is also on GitHub: VBA.RowNumbers

MS Access SQL pagination with a query (no unique identifier) or ROW_NUMBER?

I am trying to grab 100 rows at a time from a SQL query and use them for pagination. The query returns ~2000 rows from a table with 100,000+ rows. However, the table does not have a unique identifier.
SELECT TOP 100 * FROM tbl_Items WHERE tbl_Items.Repair_Required = true
I have looked into using ROW_NUMBER but it seems like that's not available in MS Access. I have also looked into creating a custom row_number using "self-join" as answered by Gord Thompson here: Access query producing results like ROW_NUMBER() in T-SQL. However, joining my 100,000+ table with itself would be not be easy on performance.
What are my options?
Here is a method using a collection and it works really fast:
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));
'
' 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.
Static col As New Collection
Static strGroup As String
On Error GoTo Err_RowCounter
If booReset = True Or strGroup <> strGroupKey Then
Set col = Nothing
strGroup = strGroupKey
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
Please study the in-line comments and examples.
Of course, you would apply it to the query with the 2000 records, not the source table(s).