My database is made for skiing competitions. The idea is that you can fill in the times people ski, and the databse automatically calculates what kind of medal you earned based on someone who set the time first, your gender and your age. I have made a form that makes it able to sign up and give all the results.
The only problem I'm having now is when signing someone up, it must be ordered on age. I did that, but now the autonumbering is all messed up.
What I want is that I can put all the names of the competitors in, and after that I want to have a query which I can choose that assigns all of the starting numbers. Even when the numbers are allready assigned I want to reset it and assign them again if someone joins in lately. I don't want to have to delete the auto numbering field and make it again because most of the time I won't be using it myself but other people will, so I want a simple push on the button that assigns it.
Thanks in advance!
Example how my database and a competition looks like
An Autonumber field is only for identifying records. No more no less.
What you need is a Priority (or Rank) field.
In your form where you display the records, run code like this for that field:
Private Sub Priority_AfterUpdate()
Dim rst As DAO.Recordset
Dim lngId As Long
Dim lngPriorityNew As Long
Dim lngPriorityFix As Long
' Save record.
Me.Dirty = False
' Prepare form.
DoCmd.Hourglass True
Me.Repaint
Me.Painting = False
' Current Id and priority.
lngId = Me!Id.Value
lngPriorityFix = Nz(Me!Priority.Value, 0)
If lngPriorityFix <= 0 Then
lngPriorityFix = 1
Me!Priority.Value = lngPriorityFix
Me.Dirty = False
End If
' Rebuild priority list.
Set rst = Me.RecordsetClone
rst.MoveFirst
While rst.EOF = False
If rst!Id.Value <> lngId Then
lngPriorityNew = lngPriorityNew + 1
If lngPriorityNew = lngPriorityFix Then
' Move this record to next lower priority.
lngPriorityNew = lngPriorityNew + 1
End If
If Nz(rst!Priority.Value, 0) = lngPriorityNew Then
' Priority hasn't changed for this record.
Else
' Assign new priority.
rst.Edit
rst!Priority.Value = lngPriorityNew
rst.Update
End If
End If
rst.MoveNext
Wend
' Reorder form and relocate record.
Me.Requery
Set rst = Me.RecordsetClone
rst.FindFirst "Id = " & lngId & ""
Me.Bookmark = rst.Bookmark
' Present form.
Me.Painting = True
DoCmd.Hourglass False
Set rst = Nothing
End Sub
Just assign a rank to any record, and records will be renumbered as and if needed.
Related
I want to duplicate a form with 3 subforms - to explain it simple: imagine a recipe (main form: some general data; sub form 1: list of ingredients, sub form 2: instructions; sub form 3: prices; sometimes the recipes change only the type of flour, so I don't want to type everything again but just have the same form with a new uniqe ID and this one change in the ingredients list)
duplicating the main form is easy, but the sub forms are empty. there are some ideas i found online, but it seems incredibly difficult (i am coding beginner), see for example Microsofts suggestion: https://support.microsoft.com/en-us/help/208824/acc2000-how-to-duplicate-a-main-form-and-its-subform-detail-records
I basically want to have the same content with a "+1" to the unique ID.
Any ideas?
Thanks!
You can have a button on the main form to run this code to copy parent record and all child records without external queries, nor a requery of the subforms.
Here you copy two subforms. Just extend it with similar code to Copy child records 3 as you have three subforms:
Private Sub CopyButton_Click()
Dim rst As DAO.Recordset
Dim rstAdd As DAO.Recordset
Dim fld As DAO.Field
Dim Count As Integer
Dim Item As Integer
Dim Bookmark As Variant
Dim OldId As Long
Dim NewId As Long
' Copy parent record.
Set rstAdd = Me.RecordsetClone
Set rst = rstAdd.Clone
' Move to current record.
rst.Bookmark = Me.Bookmark
OldId = rst!Id.Value
With rstAdd
.AddNew
For Each fld In .Fields
With fld
If .Attributes And dbAutoIncrField Then
' Skip Autonumber or GUID field.
Else
.Value = rst.Fields(.Name).Value
End If
End With
Next
.Update
' Pick Id of the new record.
.MoveLast
NewId = !Id.Value
End With
' Store location of new record.
Bookmark = rstAdd.Bookmark
' Copy child records 1.
Set rstAdd = Me!subChild1.Form.RecordsetClone
Set rst = rstAdd.Clone
If rstAdd.RecordCount > 0 Then
rstAdd.MoveLast
rstAdd.MoveFirst
End If
Count = rstAdd.RecordCount
For Item = 1 To Count
With rstAdd
.AddNew
For Each fld In .Fields
With fld
If .Attributes And dbAutoIncrField Then
' Skip Autonumber or GUID field.
ElseIf .Name = "FK" Then
' Skip master/child field.
.Value = NewId
Else
.Value = rst.Fields(.Name).Value
End If
End With
Next
.Update
End With
rst.MoveNext
Next
' Copy child records 2.
Set rstAdd = Me!subChild2.Form.RecordsetClone
Set rst = rstAdd.Clone
If rstAdd.RecordCount > 0 Then
rstAdd.MoveLast
rstAdd.MoveFirst
End If
Count = rstAdd.RecordCount
For Item = 1 To Count
With rstAdd
.AddNew
For Each fld In .Fields
With fld
If .Attributes And dbAutoIncrField Then
' Skip Autonumber or GUID field.
ElseIf .Name = "FK" Then
' Skip master/child field.
.Value = NewId
Else
.Value = rst.Fields(.Name).Value
End If
End With
Next
.Update
End With
rst.MoveNext
Next
rst.Close
rstAdd.Close
' Move to the new recordcopy.
Me.Bookmark = Bookmark
Set fld = Nothing
Set rstAdd = Nothing
Set rst = Nothing
End Sub
Note please, that subChildx represent the names of the subform controls, which may differ from the names of the subforms themselves.
I have been looking for some code that creates a calendar year and will take data from a table and place it in the corresponding date on the calendar. I found some code online (from an older version of access) that pretty much fit the bill, with some modifications it does exactly what I need it to do. Originally, the code pulled data from one table and it was set up to run on the current year. I use two queries, qr_SafetyCal and qr_SafetyCal2, to refine data from the one table. The first query prioritizes the data and eliminates multiple events on any given day. The second query uses the results from the first and specifies the year in the query criteria.
The code works flawlessly as long as I set the year criteria in the qr_SafetyCal2 and specify the first day, ex. 1/1/2017 (datStart) in the underlying code of the calendar year I want displayed.
After getting the code squared away I created a pop up form the user to select the year for the report but when I run the report I get the following error, Runtime Error 3061 too few parameters expected 1.
From what I have been able to research, I believe I changed the dynamic of the code when I referenced the form in the query criteria that the DAO Recordset Used.
As I understand it, the criteria in the query is not passed to the rs and therefore needs to be declared in the code. What I can't figure out is how to declare the variables in the code through reference to the form. I hope that makes some sense to somebody, long explanation but hard to describe something you don't understand.
Below is all the code and you will see some things I've rem'd out that I have tried but did not work. Any help would be greatly appreciated. I apologize ahead of time if the code is not formatted correctly.
Option Compare Database
Option Explicit
Private m_strCTLLabel As String
Private m_strCTLLabelHeader As String
Private colCalendarDates As Collection
Function getCalendarData() As Boolean
Dim rs As DAO.Recordset
Dim strDate As String
Dim strCode As String
Dim i As Integer
'Dim qdf As DAO.QueryDef
'Set qdf = CurrentDb.QueryDef("qr_SafetyCal2")
'qdf.Parameters("[Forms]![fr_SafetyCal]![cboYear]") = [Forms]![fr_SafetyCal]![cboYear]
'Set rs = qdf.OpenRecordset("qr_SafetyCal2", dbOpenDynaset)
Set rs = CurrentDb.OpenRecordset("qr_SafetyCal2", dbOpenDynaset)
Set colCalendarDates = New Collection
With rs
If (Not .BOF) Or (Not .EOF) Then
.MoveLast
.MoveFirst
End If
If .RecordCount > 0 Then
For i = 1 To .RecordCount
strDate = .Fields("Date")
strCode = .Fields("ShortName")
colCalendarDates.Add strCode, strDate
.MoveNext
Next i
End If
.Close
End With
'Return of dates and data collection form qr_SafetyCal2
Set rs = Nothing
End Function
Public Sub loadReportYearCalendar(theReport As Report)
Dim i As Integer
Dim datStart As Date
Dim rptControl As Report
m_strCTLLabel = "labelCELL"
m_strCTLLabelHeader = "labelDAY"
'Load calendar data for the specified year into the collection
Call getCalendarData
With theReport
'Get the first month of the specified year
datStart = "1/1/2017" '"1/1/" & Year(Date), "1/1/" & Forms!
[fr_SafetyCal]![cboYear], Forms![fr_SafetyCal]![txtCalYear]
'Add the specified year to the report's label
.Controls("labelCalendarHeaderLine2").Caption = Year(datStart) & "
iCalendar"
For i = 1 To 12
'Set pointer to subreport control hosting the mini-calendar
Set rptControl = .Controls("childCalendarMonth" & i).Report
'Run procedure to populate control with it's respective year
Call loadReportCalendar(rptControl, datStart)
'Reset and obtain first day of the following month
datStart = DateAdd("m", 1, datStart)
Next i
End With
'Clean up
Set colCalendarDates = Nothing
Set rptControl = Nothing
End Sub
Public Sub loadReportCalendar(theReport As Report, Optional StartDate As
Date, Optional theHeaderColor As Variant)
Dim i As Integer
Dim intCalDay As Integer
Dim datStartDate As Date
Dim intWeekDay As Integer
datStartDate = StartDate
intWeekDay = Weekday(datStartDate)
With theReport
.Controls("labelMONTH").Caption = Format(StartDate, "mmmm")
'Change the day label's backcolor if necessary
If Not (IsMissing(theHeaderColor)) Then
For i = 1 To 7
.Controls("labelDayHeader" & i).BackColor = theHeaderColor
Next
End If
For i = 1 To 42
With .Controls(m_strCTLLabel & i)
If (i >= intWeekDay) And (Month(StartDate) =
Month(datStartDate)) Then
If (datStartDate = Date) Then
.BackColor = 14277081
End If
On Error Resume Next
Dim strCaption As String
Dim strKey As String
strKey = datStartDate
strCaption = ""
strCaption = colCalendarDates.Item(strKey)
colCalendarDates.Remove strKey
'Set back color to grean on days in the past that have
no corresponding event
If (datStartDate < Date) And (strCaption = vbNullString) Then
.Caption = Day(datStartDate)
.Bold = False
.BackColor = vbGreen
.ForeColor = vbWhite
.Heavy = True
'Do not set a back color for days in the future
ElseIf (datStartDate > Date) And (strCaption = vbNullString) Then
.Caption = Day(datStartDate)
.Bold = False
'Set the corresponding labels and formats for each specified event
Else
.Caption = strCaption
.Bold = True
Select Case strCaption
Case "FA"
.BackColor = vbYellow
.ForeColor = 0
.LeftMargin = 0
.TextAlign = 2
Case "FAM"
.BackColor = vbYellow
.ForeColor = 0
.LeftMargin = 0
.TextAlign = 2
.Heavy = True
Case "LTA"
.BackColor = vbRed
.ForeColor = vbWhite
.LeftMargin = 0
.TextAlign = 2
Case "MED"
.BackColor = vbRed
.ForeColor = vbWhite
.LeftMargin = 0
.TextAlign = 2
End Select
End If
datStartDate = DateAdd("d", 1, datStartDate)
Else
.Caption = ""
End If
End With
Next i
End With
End Sub
Here is SQL for the two queries, the first is qr_SafetyCal and the second is qr_SafetyCal2:
SELECT tb_CaseLog.Date, Max(tb_Treatment.Priority) AS MaxOfPriority,
Count(tb_Treatment.TreatmentID) AS CountOfTreatmentID
FROM tb_Treatment INNER JOIN tb_CaseLog ON tb_Treatment.TreatmentID =
tb_CaseLog.Treatment
GROUP BY tb_CaseLog.Date;
SELECT qr_SafetyCal.Date, tb_Treatment.ShortName,
qr_SafetyCal.CountOfTreatmentID AS [Count], Year([Date]) AS CalYear
FROM qr_SafetyCal INNER JOIN tb_Treatment ON qr_SafetyCal.MaxOfPriority =
tb_Treatment.Priority;
No need to reference QueryDef.
Open the recordset object with filtered dataset by referencing the combobox like:
Set rs = CurrentDb.OpenRecordset("SELECT * FROM qr_SafetyCal2 WHERE CalYear=" & [Forms]![fr_SafetyCal]![cboYear], dbOpenDynaset)
or if the code is behind the form:
Set rs = CurrentDb.OpenRecordset("SELECT * FROM qr_SafetyCal2 WHERE CalYear=" & Me.[cboYear], dbOpenDynaset)
Both examples assume the field is a number type.
If there is no field in query with the year value, it can be extracted from date value field in the VBA construct:
Set rs = CurrentDb.OpenRecordset("SELECT * FROM qr_SafetyCal2 WHERE Year([YourFieldnameHere])=" & [Forms]![fr_SafetyCal]![cboYear], dbOpenDynaset)
Code for setting datStart variable:
'Get the first month of the specified year
datStart = "1/1/" & Forms![fr_SafetyCal].[cboYear]
I have the problem that the combobox in access 2010 displays just 1249 values of the 1278. Is there a possibility to increase the max number of values in a combobox in access?
Here is a code sample:
If not rs.EOF Then
rs.MoveFirst
frm.FName.RowSource = ""
frm.FNameLux.RowSource = ""
Do Until rs.EOF
If rs![id] <> -1 And rs![id] <> -2 Then
If (rs!KID <> 2 And rs!KID <> 8) Then
If IsNull(rs![Name]) = False Then
frm.FName.AddItem rs![Name] & ";" & rs![id]
Debug.Print rs!Name 'The program writes all values in the combobox, but when I look in the form, I don't see all values
End If
End If
If (rs!KID = 2 Or rs!KID = 8) Then
If IsNull(rs![Name]) = False Then
frm.FNameLux.AddItem rs![Name] & ";" & rs![id]
End If
End If
End If
rs.MoveNext
i = i + 1
Loop
End If
rs is the recordset. Is there any idea how to solve it or what I have to do?
Apparently the RowSource property for RowSourceType = Value list is limited to 16bit integer length (2^15 = 32768) or a bit below.
Test code for a 2-column combobox:
Private Sub btValues_Click()
Dim i As Long
DoCmd.Hourglass True
Me.cboValues.RowSource = ""
For i = 1 To 5000
Me.cboValues.AddItem "Number " & Format(i, "0000") & ";" & i
Next i
DoCmd.Hourglass False
Debug.Print Len(Me.cboValues.RowSource)
End Sub
The combobox is filled up until "Number 1991", output is 32739.
So the problem is not the number of rows, but the total string length. If I shorten the text, it goes up to "Nr 2604" (32744 chars).
You'll have to use RowSourceType = Table/query to show all items.
Edit
Create queries as rowsource for the comboboxes. As far as I can see, there is nothing in your code that cannot be done in a WHERE clause.
E.g. for FName
SELECT Name, id
FROM yourTable
WHERE id <> -1 AND id <> -2
AND KID <> 2 AND KID <> 8
AND Name IS NOT NULL
If your VBA code could not be recreated in SQL, you'd have to insert the recordset rows you want into a temp table, and use this table as rowsource.
I have a Lease Table with Start and End Dates. I need to add the records to fill the missing date range. To calculate the Vacancy of the property. I am working in Access.
You can simply loop the table - as in this example inserting missing hours:
Public Function FillWindLog()
Dim dbs As DAO.Database
Dim rst As DAO.Recordset
Dim datMin As Date
Dim datMax As Date
Dim datLog As Date
Dim datNew As Date
Dim datOld As Date
Set dbs = CurrentDb
Set rst = dbs.OpenRecordset("Select * From tblWindLog Order By DateLog")
With rst
' Find first and last logging date.
.MoveLast
datMax = !DateLog.value
.MoveFirst
datMin = !DateLog.value
' Set initial low value of empty interval.
datOld = datMin
' Set initial high value of current empty interval.
datLog = datMin
.MoveNext
' Locate empty intervals.
' Stop when reaching the last of the old records.
While .EOF = False And datLog < datMax
' Set high value of a possible empty interval.
datLog = !DateLog.value
' Increment low value of possible empty interval by one hour.
datNew = DateAdd("h", 1, datOld)
' Fill empty intervals with hourly recordings of Null values.
Do While DateDiff("h", datNew, datLog) >= 1 And datNew < datMax
.AddNew
!DateLog.value = datNew
.Update
datNew = DateAdd("h", 1, datNew)
Loop
' Set low value of the next possible empty interval.
datOld = datLog
.MoveNext
Wend
.Close
End With
Set rst = Nothing
Set dbs = Nothing
End Function
You should be able to modify it to insert full dates instead of hours.
When there is only one record, this expression gives correct calculation, but when there are more than one record the values of last record calculated is reflected in all Total_Time (unbound text box).I have given on load and on open code of the report. Please help me.
Private Sub Report_Load()
strSQL = "SELECT * FROM [q_1ltduty]"
Set db = CurrentDb
Set rs = db.OpenRecordset(strSQL)
rs.MoveFirst
Do While Not rs.EOF
'Assigning values of fields to varia
strtime1 = Op_Time
strtime2 = Cl_Time
'This is a simple expression my code has some more detailed calculations
strhrs = strtime2 - strtime1
strtotalhrs = strhrs
'Printing the variable in Total_Time textbox(unbound)
Me.Total_Time.Value = strtotalhrs
rs.MoveNext
Loop
rs.Close
db.Close
Set db = Nothing
Set rs = Nothing
End Sub
Private Sub Report_Open(Cancel As Integer)
strSQL = "SELECT * FROM [q_1ltduty]"
Me.RecordSource = strSQL
Debug.Print strSQL
Exit Sub
ErrHandler:
MsgBox Err.Description
End Sub
Your variable strtotalhrs contains only the value of strhrs for one record, so each time you go through the loop, the value for the current record erases the value for the previous record. What you should do instead of erasing the value is adding to it.
Before the loop (if it has not already been done):
strtotalhrs = 0
then in the loop, instead of strtotalhrs = strhrs:
strtotalhrs = strtotalhrs + strhrs
and that should give you the sum total instead of the last value.