MS Access- order of occurrence - ms-access

I am struggling with the following thing in MS Access: I want to assign each record an nth order of its occurrence (1st, 2nd time NOT TOTAL number of occurrences).
Comparing to Excel, it should work like countif with moving range. For example, if the values are stored in column B that would be
=countif($B$1:B1,B1)

You can use my RowCounter function.
Please study the in-line comments for typical usage:
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

Consider a correlated count subquery or conditional DCount for SELECT statements. Below assumes you have an autonumber field, ID, in myTable:
SELECT t.[value], (SELECT Count(*) FROM myTable
WHERE sub.[value] = t.[value]
AND sub.ID <= t.ID) As value_rank
FROM myTable t
SELECT t.[value],
DCount("*", "myTable",
"[value] = " & t.[value] & " AND ID <= " & t.ID) As value_rank
FROM myTable t
For UPDATE queries, you would need the DCount for it to be an updateable query:
UPDATE myTable t
SET t.value = DCount("*", "myTable",
"[value] = " & t.value & " AND ID <= " & t.ID)
If value is a string, wrap concatenation with single quotes: ... "[value] = '" & t.value & "' ... If value is a date, wrap with hashtags: ... "[value] = #" & t.value & "# ...

Related

Access cannot close after 100s of function calls - Recordset sees to be "open" although closed

I need to calculate roughly 100 medians in an access database and have a function (see code below)
After calling this many times with the code
Nz(DMedian("Price", "Qry91_Cad_by", "[Cad ID]='" & rst![Cad ID] & "'"), 0)
I cannot quit Access any more and need to kill it with the task manager (as there are open connections)
When compacting the database, I get the error "You attemted to open a database that is already open by user 'Admin' .....
You can close the database but Access itself needs to be killed
Any Ideas what's wrong?
...
Public Function DMedian( _
ByVal strField As String, ByVal strDomain As String, _
Optional ByVal strCriteria As String) As Variant
' Purpose:
' To calculate the median value
' for a field in a table or query.
' In:
' strField: the field.
' strDomain: the table or query.
' strCriteria: an optional WHERE clause to
' apply to the table or query.
' Out:
' Return value: the median, if successful;
' Otherwise, an Error value.
Dim db As DAO.Database
Dim rstDomain As DAO.Recordset
Dim strSQL As String
Dim varMedian As Variant
Dim intFieldType As Integer
Dim intRecords As Integer
Const errAppTypeError = 3169
'On Error GoTo HandleErr
Set db = CurrentDb()
' Initialize return value.
varMedian = Null
' Build SQL string for recordset.
strSQL = "SELECT " & strField & " FROM " & strDomain
' Only use a WHERE clause if one is passed in.
If Len(strCriteria) > 0 Then
strSQL = strSQL & " WHERE " & strCriteria
End If
strSQL = strSQL & " ORDER BY " & strField
Set rstDomain = db.OpenRecordset(strSQL, dbOpenSnapshot)
' Check the data type of the median field.
intFieldType = rstDomain.Fields(strField).Type
Select Case intFieldType
Case dbByte, dbInteger, dbLong, _
dbCurrency, dbSingle, dbDouble, dbDate
' Numeric field.
If Not rstDomain.EOF Then
rstDomain.MoveLast
intRecords = rstDomain.RecordCount
' Start from the first record.
rstDomain.MoveFirst
If (intRecords Mod 2) = 0 Then
' Even number of records.
' No middle record, so move to the
' record right before the middle.
rstDomain.Move ((intRecords \ 2) - 1)
varMedian = rstDomain.Fields(strField)
' Now move to the next record, the
' one right after the middle.
rstDomain.MoveNext
' And average the two values.
varMedian = _
(varMedian + rstDomain.Fields(strField)) / 2
' Make sure you return a date, even when
' averaging two dates.
If intFieldType = dbDate And Not IsNull(varMedian) Then
varMedian = CDate(varMedian)
End If
Else
' Odd number or records.
' Move to the middle record and return its value.
rstDomain.Move ((intRecords \ 2))
varMedian = rstDomain.Fields(strField)
End If
Else
' No records; return Null.
varMedian = Null
End If
Case Else
' Non-numeric field; so raise an app error.
Err.Raise errAppTypeError
End Select
DMedian = varMedian
ExitHere:
'On Error Resume Next
rstDomain.Close
Set rstDomain = Nothing
db.Close
Set db = Nothing
Exit Function
HandleErr:
' Return an error value.
DMedian = CVErr(Err.Number)
Resume ExitHere
End Function
...

Return a incremental group number per group in MS Access

I need help to create a query in Access to incrementally number groups of rows, grouped on a common date and keep the "group numbers" increment on the next date like showing in the Result column.
Date |ID |Result
2017/01/09 |809 | 1
2017/01/09 |810 | 1
2017/01/09 |826 | 1
2017/01/10 |826 | 2
2017/01/11 |809 | 3
2017/01/11 |810 | 3
2013/01/11 |826 | 3
2017/01/12 |809 | 4
2017/01/12 |810 | 4
2017/01/12 |826 | 4
Thank you
Here is one approach:
SELECT A.*, (SELECT Count(*) FROM (SELECT DISTINCT [Date] FROM Table1) AS Q1 WHERE A.Date>=[Date]) AS GrpSeq FROM Table1 AS A;
Another is with properties of textbox in Group Header on report:
RunningSum: OverGroup
ControlSource: =1
You can use this function which is for exactly the purpose. See in-line comments for typical usage:
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
For your case it could be:
SELECT RowCounter(CStr([ID]), False, Format([Date], "yyyymmdd") AS RowID, *
FROM YourTable
WHERE (RowCounter(CStr([ID]), False) <> RowCounter("", True));

Assign Rank/Index to Records in Sorted MS Access Query

I have an MS Access query which I'm sorting using data which cannot be output for confidentiality reasons, however, I need to include a rank or index in the output such that the sort order can be maintained.
Currently, my approach is loosely as follows:
Dim cdb As DAO.Database
Dim rst As DAO.Recordset
Dim dst As DAO.Recordset
Dim idx As Long
Set cdb = CurrentDb
Set rst = cdb.OpenRecordset("SELECT Field1, Field2, Field3, Field4, Field5 FROM MyTable ORDER BY Field6")
Set dst = cdb.OpenRecordset("MyOutputTable")
idx = 1
If Not rst.EOF Then
rst.MoveFirst
Do Until rst.EOF
dst.AddNew
dst!Field1 = rst!Field1
dst!Field2 = rst!Field2
dst!Field3 = rst!Field3
dst!Field4 = rst!Field4
dst!Field5 = rst!Field5
dst!Rank = idx
dst.Update
idx = 1 + idx
rst.MoveNext
Loop
End If
dst.Close
rst.Close
Set dst = Nothing
Set rst = Nothing
Set cdb = Nothing
However:
This necessitates creating an output table with a pre-existing 'Rank' field to house the results.
Populating the value of every individual field in the output table within the Do loop is incredibly tedious... there must be a better way!
Therefore, my question is whether this result can be obtained using only a query, and without the mundane VBA?
Many thanks in advance for your time & help.
Yes, you can use a query to achieve this result, by using a subquery:
SELECT Field1, Field2, Field3, Field4, Field5,
(
SELECT Count(s.Field6)
FROM MyTable s
WHERE s.Field6 <= t.Field6
) As Rank
FROM MyTable t
ORDER BY Field6
Note that this will have a substantial impact on performance, as the subquery needs to be reran for every row.
Also note that for rows with an equal value for Field6, their rank will be equal, in contrast to your VBA code where their rank is not equal.
You can use my RowCounter function. See in-line comments for typical usage:
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
Learning from #Gustav's solution, I realised that since I'm not actually counting records aggregated by a key, but rather only assigning a rank or index to a sorted set, I could use the following simple VBA code:
Function RowRank(Optional varTmp, Optional bolRst As Boolean) As Long
Static lngRow As Long
If bolRst Then lngRow = 0 Else lngRow = 1 + lngRow
RowRank = lngRow
End Function
Evaluated using the following SQL statement:
SELECT
t.*, RowRank([Field6]) AS Rank
FROM
(SELECT * FROM MyTable ORDER BY Field6) AS t
WHERE
RowRank("",True) = 0
Here, the RowRank function is initialised in the WHERE clause, and the first argument supplied to the RowRank function in the SELECT statement is merely a dummy argument in order to force the RowRank function to be evaluated for every record in the table t.

SQL query not working in Access

My first time using Access
The below query works in SQL Server but when I bring it into access I get the below error message.
DECLARE #CandidateNumber INT
SET #CandidateNumber = 5921368
UPDATE XXX
SET #CandidateNumber = CandidateNumber = #CandidateNumber + 1
GO
Error message: invalid sql statement expected 'delete' 'Insert','Select','Update'
It does not work because Access uses a different dialect of SQL than SQL Server. In particular Access SQL (JET) does not support DECLARE-ing variables.
Unfortunately, JET SQL is not well-documented by Microsoft, but there are third-party resources available (for example, a JET Database Wikibook).
Perhaps all you need is a query with a row counter.
You can use this function and just add the CandidateNumber value:
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
See in-line comments for typical usage.
If you are working with a table linked from SQL-Server, you can use a pass-through query in Access. This type of query is not exectued by the Access engine (JetEngine) but is sent directly to SQL-Server which executes it.
If you are deling with a true Access query, then use a parameter.
See: Passing parameter to query for Access database

Add autonumber field to query that returns more than 5000 records

Adding auto-number field in that query makes ms-access not responding. I used
SELECT (SELECT COUNT(*) FROM .....), * FROM ...
My query has non-unique value in every column. I just want to add 1,2,3,4,... in a new column. Please help me solve my problem.
Sorry, missed the query part for no known reason, so here is a completely different answer ...
Use this function which reads the records once only and then stores the IDs in a collection that is much faster to look up:
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
Please study the in-line documentation for typical usages including that of yours.