DMax Number Sequence Fix Gap - vba

I have this function to where it tries to auto sequence a number starting at the number 8000 and the number seeds back to 8000 every day. The function also attempts to ensure that there is no gap so if there is a manual entry and the number creates a gap the field will not sequence from the manual entry. But I cannot seem to get the code to work as it just stays at the same number from the previous entry and does not increase.
Public Function fRetNextInSequence() As Long
Dim MyDB As DAO.Database
Dim rst As DAO.Recordset
Dim rstClone As DAO.Recordset
'If there are no Records in tblData, then have the Function return 8000
If DCount("strSerialNumber", "tblOrderData", "dtmDateOrdered=#" & Date & "#") = 0 Then
fRetNextInSequence = 8000
Exit Function
End If
Set MyDB = CurrentDb
Set rst = MyDB.OpenRecordset("tblOrderData", dbOpenSnapshot)
Set rstClone = rst.Clone
rst.MoveLast 'Move to Last Record [MyNum]
With rstClone 'Move to Next-to-Last Record [MyNum]
.MoveLast
.Move -1 'Clone now at Next-to-Last Record [MyNum]
End With
With rst
Do While Not rstClone.BOF
If Abs(![strSerialNumber] - rstClone![strSerialNumber]) > 1 Then
fRetNextInSequence = (rstClone![strSerialNumber] + 1) 'Found the Gap!
Exit Function
End If
.MovePrevious 'Move in sync, 1 Record apart
rstClone.MovePrevious
Loop
End With
rst.MoveLast
fRetNextInSequence = (rst![strSerialNumber] + 1) 'No Gap found, return next number in sequence!
rstClone.Close
rst.Close
Set rstClone = Nothing
Set rst = Nothing
End Function
If SOS = "ES-S" Then
SerialNbrValue = fRetNextInSequence
'SerialNbrValue = Val(Nz(DMax("strSerialNumber", "tblOrderData", "dtmDateOrdered=#" & Date & "#"), 7999)) + 1
Else
SerialNbrValue = ""
End If

Exiting the function from the loop bypasses the lines to close and clear the recordset objects. That isn't causing the issue but why have them if they aren't used everytime the recordsets are opened?
The following revised procedure worked for me to return appropriate sequence when I call the function from the VBA Immediate Window:
Public Function fRetNextInSequence() As Long
Dim MyDB As DAO.Database
Dim rst As DAO.Recordset
Dim rstClone As DAO.Recordset
If Nz(DMin("strSerialNumber", "tblOrderData", "dtmDateOrdered=Date()"), 0) <> 8000 Then
'If there are no Records or the gap is 8000 for current date, Function returns 8000
fRetNextInSequence = 8000
Else
Set MyDB = CurrentDb
Set rst = MyDB.OpenRecordset("SELECT strSerialNumber FROM tblOrderData WHERE dtmDateOrdered=Date() ORDER BY strSerialNumber", dbOpenSnapshot)
Set rstClone = rst.Clone
rst.MoveLast 'Move to Last Record [MyNum]
With rstClone 'Move to Next-to-Last Record [MyNum]
.MoveLast
.Move -1 'Clone now at Next-to-Last Record [MyNum]
End With
With rst
Do While Not rstClone.BOF
If Abs(![strSerialNumber] - rstClone![strSerialNumber]) > 1 Then
'Found the Gap!
fRetNextInSequence = (rstClone![strSerialNumber] + 1)
Exit Do
End If
.MovePrevious 'Move in sync, 1 Record apart
rstClone.MovePrevious
Loop
End With
If fRetNextInSequence = 0 Then
'No Gap found, return next number in sequence!
rst.MoveLast
fRetNextInSequence = (rst![strSerialNumber] + 1)
End If
rstClone.Close
rst.Close
Set rstClone = Nothing
Set rst = Nothing
End If
End Function

Related

Debug.Print all data in a table

I am trying to use recordset code to loop through all the fields in a table and debug.print their values and field names in an order you would naturally read the table ie from left to right across columns then onto the row below
I have accomplished what I'm trying to do but only for the first row. This is the code:
Sub RecordSets()
Dim db As Database
Dim rs As Recordset
Dim i As Long
Set db = CurrentDb
Set rs = db.OpenRecordset("tbl1")
For i = 0 To rs.Fields.Count - 1
Debug.Print rs.Fields(i).Name
Debug.Print rs.Fields(i).Value
Next
rs.Close
db.Close
End Sub
Immediate window produces following result:
Category
Clothing
Item
Shirt
Price
5
This is the top row and is exactly as I want. But I cannot get any code to work accomplish this exact same thing for the other rows. I am 99% sure I need to use a Do Until .EOF loop in conjunction with the For...Next loop but I can't get the results whatever I try or I lock access up in an infinite query.
Thanks for your help
Untested:
Sub RecordSets()
Const SEP as String = vbTab
Dim db As Database
Dim rs As Recordset, numFlds As Long
Dim i As Long, s As String, sp as string
Set db = CurrentDb
Set rs = db.OpenRecordset("tbl1")
numFlds = rs.Fields.Count
'print the headers (field names)
For i = 0 To numFlds - 1
s = s & sp & rs.Fields(i).Name
sp = SEP '<< add separator for subsequent items
Next
Debug.Print s
'print the data
sp = "" '<< clear the separator
Do While Not rs.EOF
For i = 0 To numFlds - 1
s = s & sp & rs.Fields(i).Name
sp = SEP
Next
Debug.Print s
rs.MoveNext
Loop
rs.Close
db.Close
End Sub

Run time Error 3201 when reading Database and missing the last entry

I am currently struggling with this piece of Code:
While receiver = data.Fields("Contact")
If first Then
first = False
strSig = Replace(strSig, ID, data.Fields("ID") & ID)
Else
strSig = Replace(strSig, ID, ", " & data.Fields("ID") & ID)
End If
data.MoveNext
Wend
It is not reading the last database entry.
My complete code is doing the following:
Read Database
Read an HTML File
Search for multiple IDs for a person and aggregate those
Replace the IDs with a placeholder in the IDs
Send the Email
The process does work except for for the last entry. For that entry I receive a
3021 Run Time Error - No Current Record.
Here is an example of how to loop through a recordset:
Option Explicit
Sub recordsetDemo()
'can use the name of a table or of a query, or a specific SQL query:
Const rs_Source = "select * from tblYourTable"
Dim rs As Recordset
Set rs = CurrentDb.OpenRecordset(rs_Source) 'open the recordset
With rs 'refer to the RS with "." dots instead of the full name "rs."
If Not .EOF Then .MoveFirst 'move to the first record
Do While Not .EOF 'keep doing this until the end of the recordset
Debug.Print !myField1, !myField2 'do "something" here with the data.
.MoveNext 'move to the next record
Loop 'loop will end if there's no "next record"
.Close 'close the recordset
End With
Set rs = Nothing 'clear the variable
End Sub
A rough adaptation using your example:
Sub recordsetDemo()
Dim data As Recordset
Set data = CurrentDb.OpenRecordset("YourTableOrQueryName") 'open recordset
'***however you setup your "Data" recordset could replace the above code***
With data
If .EOF Then 'check if there's data
MsgBox "No Data Found!"
Exit Sub
End If
.MoveFirst 'move to the first record
Do While Not .EOF 'keep doing this until the end of the recordset
If first Then
first = False
strSig = Replace(strSig, id, !id & id)
Else
strSig = Replace(strSig, id, ", " & !id & id)
End If
.MoveNext 'move to the next record
Loop 'loop will end if there's no "next record"
.Close 'close the recordset
End With
Set rs = Nothing 'clear the variable
End Sub
That's all I can do given the information you provided.

CopyFromRecordSet in reverse

I'm developing an Access database and have some code on a form button that takes the contents of a recordset and exports it to an excel document. The following code works however I have been asked that the export data be reversed on the worksheet.
Set qdef = db.QueryDefs("Inspection_Detail_Crosstab")
qdef![Tag_No_Param] = Tag_Number.Value
Set rs = qdef.OpenRecordset()
EquipmentCellSt = (Col & EquipmentCell)
With wsheet
.Range(EquipmentCellSt).CopyFromRecordset rs
End With
So rather than(as it does right now):
- item 1
- item 2
- item 3
it exports:
- item 3
- item 2
- item 1
I thought a method of doing this would be to:
With wsheet
rs.MoveLast
.Range(EquipmentCellSt).CopyFromRecordset rs
rs.MovePrevious
End With
But adding the MoveLast and MovePrevious just seems to lock up the program.
You can manually export the recordset by iterating through the records in reverse:
Dim rowNum as Long
Dim columnNum As Long
Dim fld As Field
columnNum = 0
rowNum = 0
'stupid client-side sorting, because management
rs.MoveLast
Do While Not rs.BOF
For Each fld In rs.Fields
wsheet.Range(EquipmentCellSt).Offset(rowNum, columnNum).Value = fld.Value
columnNum = columnNum + 1
Next
rowNum = rowNum + 1
columnNum = 0
rs.MovePrevious
Loop

4 button captions through Loop from table recordset in vba access

I have a form named frmPUCFinalize with four buttons named btn1,btn1,btn2,btn4 and also have a table (tblStatus) where 4 caption name are stored in single field named "Button".
I want to replace all 4 buttons captions of frmPUCFinalize with each recordset from table field (Field Name : Button) using loop or other method.
I tried following code but couldn't succeed.
Private Sub Form_Load()
Dim rst As Recordset
Dim mSQL As String
mSQL = "SELECT tblStatus.Button FROM tblStatus WHERE (((tblStatus.RoleID)=4) AND ((tblStatus.Form)='frmPUCFinalize')) ORDER BY tblStatus.Button;"
Set rst = CurrentDb.OpenRecordset(mSQL)
x = 1
Y = 4 'maximun 4 buttons
rst.MoveFirst
Do While (rst.BOF = False And rst.EOF = False) And x < Y + 1
Me("btn" & x).Caption = rst!Button
x = x + 1
rst.MoveNext
Loop
rst.Close
End Sub
Try this:
Private Sub Form_Load()
Dim rst As Recordset
Dim mSQL As String
Dim idx As Long
mSQL = "SELECT tblStatus.Button FROM tblStatus WHERE (((tblStatus.RoleID)=4) AND ((tblStatus.Form)='frmPUCFinalize')) ORDER BY tblStatus.Button;"
Set rst = CurrentDb.OpenRecordset(mSQL)
If rst.EOF Then
rst.Close
Exit Sub
End If
With rst
.MoveLast
.MoveFirst
End With
For idx = 1 to rst.RecordCount
Me.Controls("btn" & idx).Caption = rst![Button]
rst.MoveNext
Next idx
rst.Close
End Sub

VBA - Return Results in Sheet 2 if Sheet 1 is full

I'm currently running a SQL stored procedure from an Excel Macro. The count of returned records exceeds the maximum rows for one sheet. How can I transfer the overflow results to a second sheet?
Sub Button1_Click()
Dim con As ADODB.Connection
Dim cmd As ADODB.Command
Dim rs As ADODB.Recordset
Dim par As String
Dim WSP1 As Worksheet
Set con = New ADODB.Connection
Set cmd = New ADODB.Command
Set rs = New ADODB.Recordset
Application.DisplayStatusBar = True
Application.StatusBar = "Contacting SQL Server..."
' Remove any values in the cells where we
' want to put our Stored Procedure's results.
Dim rngRange As Range
Set rngRange = Range(Cells(8, 2), Cells(Rows.Count, 1)).EntireRow
rngRange.ClearContents
' Log into our SQL Server, and run the Stored Procedure
con.Open "Provider=SQLOLEDB;Data Source=67.09;Initial Catalog=TEST..."
cmd.ActiveConnection = con
Application.StatusBar = "Running stored procedure..."
cmd.CommandText = "SP_Billing"
Set rs = cmd.Execute(, , adCmdStoredProc)
' Copy the results to cell B7 on the first Worksheet
Set WSP1 = Worksheets(1)
WSP1.Activate
If rs.EOF = False Then WSP1.Cells(8, 2).CopyFromRecordset rs
rs.Close
Set rs = Nothing
Set cmd = Nothing
con.Close
Set con = Nothing
Application.StatusBar = "Data successfully updated."
End Sub
Just pass the MaxRows parameter to .CopyFromRecordset and loop until you hit EOF. Each call advances the cursor in the recordset, and the copy starts from the current cursor location. I'd extract it to a Sub something like...
Private Sub SplitRecordsToSheets(records As ADODB.Recordset, perSheet As Long)
Dim ws As Worksheet
Do While Not records.EOF
Set ws = Worksheets.Add
ws.Cells(8, 2).CopyFromRecordset records, perSheet
Loop
End Sub
...and then call it like this:
' Log into our SQL Server, and run the Stored Procedure
con.Open "Provider=SQLOLEDB;Data Source=67.09;Initial Catalog=TEST..."
cmd.ActiveConnection = con
Application.StatusBar = "Running stored procedure..."
cmd.CommandText = "SP_Billing"
Set rs = cmd.Execute(, , adCmdStoredProc)
SplitRecordsToSheets rs, ActiveSheet.Rows.Count - 8
If you require some custom handling while parsing through your RecordSet (such as switching pages once you have printed, say 100k rows), you can no longer use the Range.CopyFromRecordset method. Instead, you may have to iterate through the recordset yourself. Here is a small sample of how to do such a thing (without giving the whole puzzle away, of course:
Dim i_RowCount As Long
Dim a_PrintArray As Variant, rg_PrintRg As Range
Dim i_Col As Integer
Const i_MaxRows As Long = 100000
' I recommend filling everything into an Array first and then Printing the array to Excel'
' Using your existing variables also '
ReDim a_PrintArray( 1 to i_MaxRows, 1 to rs.Fields.Count )
Set sh_Current = WSP1
Do Until rs.EOF
i_RowCount = i_RowCount + 1
If i_RowCount > i_MaxRows Then 'If we hit the max, print what we have'
' Setting up the print range to match the array size '
Set rg_PrintRg = shCurrent.Cells(8, 2)
Set rg_PrintRg = Range(rg_PrintRg, rg_PrintRg.Offset(i_MaxRows - 1, rs.Fields.Count - 1))
rg_PrintRg = a_PrintArray ' Print the array into the range '
i_RowCount = 1
Set sh_Current = sh_Current.Next
ReDim a_PrintArray( 1 to i_MaxRows, 1 to rs.Fields.Count )
End If
For i_Col = 0 To rs.Fields.Count - 1
a_PrintArray(i_RowCount, i_Col) = rs.Fields(i_Col).Value
Next i_Col
rs.MoveNext
Loop
Please note this code snippit is for demonstration only. It has not been compiled and may not be optimal for your specific application. For more information on the Recordset object: https://msdn.microsoft.com/en-us/library/ms681510%28v=vs.85%29.aspx