Controlling duplicate key in Access DataBase - ms-access

i have a problem with Access DB and VB6.
I have a program to make invoices, and the invoice number is a unique key.
The problem is when two people work simultaneously in a network introducing invoices.
I need to check that the invoice number entered by each of them does not exist to avoid duplicates.
Private Sub GuardarFactura()
If InvoiceNumberExist Then
MessageBox UserControl.hWnd, "Invoice number duplicate", "Control de errores", vbExclamation
Exit Sub
End If
On Error GoTo ErrorGuardar
Dim HayTrans As Boolean
AreaDeTrabajo.BeginTrans
HayTrans = True
Screen.MousePointer = vbHourglass
With recFrasEmi
.AddNew
!Numero = teInvoiceNumber
!Fecha = CDate(teFecha)
!TotalEuros = Format(CDbl(teTotal), FormatoImporte)
.Update
.Move 0, .LastModified
End With
AreaDeTrabajo.CommitTrans
HayTrans = False
DoEvents
Screen.MousePointer = vbDefault
Exit Sub
ErrorGuardar:
If HayTrans Then AreaDeTrabajo.Rollback
Screen.MousePointer = vbDefault
MessageBox UserControl.hWnd, Err.Number & ": " & Err.Description, "Control de errores", vbExclamation
End Sub
function InvoiceNumberExist
dim RS as recordset
Sql "Select * From Facturas Where Numero='" & teInvoiceNumber & "'"
Set RS = BD.OpenRecordset(Sql)
If Not (RS.EOF And RS.BOF) Then
InvoiceNumberExist=true
else
InvoiceNumberExist=false
End If
end function
InvoiceNumberExist don't work always if users work simultaneously,
I know i can use "if Err=3022 then ...." but is possible find the duplicate number before error??
Thanks

Thanks, then i think the only solution is use on error goto:
Private Sub GuardarFactura()
On Error GoTo ErrorGuardar
Dim HayTrans As Boolean
AreaDeTrabajo.BeginTrans
HayTrans = True
Screen.MousePointer = vbHourglass
With recFrasEmi
.AddNew
!Numero = teInvoiceNumber
!Fecha = CDate(teFecha)
!TotalEuros = Format(CDbl(teTotal), FormatoImporte)
.Update
.Move 0, .LastModified
End With
AreaDeTrabajo.CommitTrans
HayTrans = False
DoEvents
Screen.MousePointer = vbDefault
Exit Sub
ErrorGuardar:
If HayTrans Then AreaDeTrabajo.Rollback
Screen.MousePointer = vbDefault
If Err=3022 Then
MessageBox UserControl.hWnd, "Invoice number duplicate", "Control de errores", vbExclamation
Else
MessageBox UserControl.hWnd, Err.Number & ": " & Err.Description, "Control de errores", vbExclamation
End If
End Sub

Related

MS Access 2016 - Check access level on Openform using Tempvars

My intent is to deny users that do not meet a certain access level access to forms. I initially had issues with error code 3265 while writing the code for:
TempVars("EmployeeType").Value = rs!EmployeeType_ID.Value
This is no longer an issue; however, I cannot get access to the form even when the appropriate user is trying to enter. I've checked the spelling of table and column names multiple times as well.
Below is my code for the login (where I'm using the tempvars), followed by the code in form Load().
Option Compare Database
Option Explicit
Private Sub btnLogin_Click()
Dim rs As Recordset
Set rs = CurrentDb.OpenRecordset("Employees", dbOpenSnapshot, dbReadOnly)
rs.FindFirst "UserName='" & Me.txtUserName & "'"
If rs.NoMatch = True Then
Me.lblWrongUser.Visible = True
Me.txtUserName.SetFocus
Exit Sub
End If
Me.lblWrongUser.Visible = False
If rs!Password <> Me.txtPassword Then
Me.lblWrongPass.Visible = True
Me.txtPassword.SetFocus
Exit Sub
End If
If IsNull(Me.txtUserName) Or IsNull(Me.txtPassword) Then
MsgBox "You must enter password or login ID.", vbOKOnly + vbInformation, "Required Data"
Me.txtUserName.SetFocus
Exit Sub
End If
Me.lblWrongPass.Visible = False
If rs!EmployeeType >= 4 Then
Dim prop As Property
On Error GoTo SetProperty
Set prop = CurrentDb.CreateProperty("AllowBypassKey", dbBoolean, False)
TempVars("UserName").Value = Me.txtUserName.Value
TempVars("EmployeeType").Value = rs!EmployeeType_ID.Value
CurrentDb.Properties.Append prop
SetProperty:
If MsgBox("Would you like to turn on the bypass key?", vbYesNo, "Allow Bypass") = vbYes Then
CurrentDb.Properties("AllowBypassKey") = True
Else
CurrentDb.Properties("AllowBypassKey") = False
End If
End If
Me.Visible = False
DoCmd.OpenForm "frmMain"
Globals.LoggingSignOn "Logon"
End Sub
Private Sub Form_Load()
Me.txtUserName = Null
Me.txtPassword = Null
Me.txtUserName.SetFocus
End Sub
Private Sub Form_Unload(Cancel As Integer)
Globals.LoggingSignOn "Logoff"
End Sub
Private Sub Form_Load()
If Nz(DLookup("HasAccess", "tbl9EmployeeAccess", "EmployeeType_ID=" & TempVars("EmployeeType") & " FormName='" & Me.Name & "'"), False) = False Then
MsgBox "You do not have access to access this location."
DoCmd.Close acForm, Me.Name
End If
End Sub
Thank you for your time, to anybody that looks into this.

Microsoft Access Compile Error: Method or data member not found

I am creating a simple login form for my Database. When I click login, the message "Compile Error: Method or data member not found" appears. How do I fix that? Thanks! Code is below
Option Compare Database
Option Explicit
Private Sub btnLogin_Click()
Dim rs As Recordset
Set rs = CurrentDb.OpenRecordset("TBL:Staff", dbOpenSnapshot, dbReadOnly)
rs.FindFirst "UserName='" & Me.txtUserName & "'"
If rs.NoMatch = True Then
Me.lblWrongUser.Visible = True
Me.txtUserName.SetFocus
Exit Sub
Me.lblWrongUser.Visible = False
If rs!Password <> Nz(Me.txtPassword, "") Then
Me.lblWrongPass.Visible = True
Me.txtPassword.SetFocus
Exit Sub
End If
Me.lblWrongPass.Visible = False
DoCmd.OpenForm "FRM:Customer"
DoCmd.Close acForm, Me.Name
End Sub
Try this.
Check username and password values have been provided, then see if they exist in the database by a simple DCount.
If the username/password exist it will return > 0 and if not, it will return 0.
Private Sub btnLogin_Click()
With Me
'Username/Password - value provided?
If IsNull(.txtUserName.Value) Or IsNull(.txtPassword.Value) Then
MsgBox "Both fields required.", vbExclamation
Exit Sub
End If
'Username exists in Table?
If DCount("*", "Staff", "UserName='" & .txtUserName.Value & "'") = 0 Then
.lblWrongUser.Visible = True
.txtUserName.SetFocus
Exit Sub
End If
'Password exists in Table?
If DCount("*", "Staff", "UserName='" & .txtUserName.Value & _
"' And Password='" & .txtPassword.Value & "'") = 0 Then
.lblWrongPass.Visible = True
.txtPassword.SetFocus
Exit Sub
End If
End With
'Code will reach here only if supplied username and passowrd are correct
With DoCmd
.OpenForm "Customer", acNormal, , , acFormPropertySettings, acWindowNormal
.Close acForm, Me.Name, acSavePrompt
End With
End Sub

Should I re-purpose subform controls on one form or just create multiple forms?

In my office of 65 people, I want to create a "portal" for all the employees out of a single .accdb file. It will allow each employee to navigate to a new "screen" from a dropdown menu.
Should I use a single form with plug-and-play subform controls in order to centralize the VBA code, or should I just use different forms?
I'm thinking it would be nice to have one form with plug-and-play subform controls. When the employee selects a new "screen", the VBA just sets the SourceObject property of each subform control and then re-arranges the subforms based on the layout of the selected "screen".
For instance, we currently use a couple of Access database forms to enter and review errors that we find in our workflow system. So in this scenario, to review the errors I would just say
SubForm1.SourceObject = "Form.ErrorCriteria"
SubForm2.SourceObject = "Form.ErrorResults"
And then I would just move them into place (these values would be pulled dynamically based upon the "screen" selected):
SubForm1.Move WindowWidth * 0.05, WindowHeight * 0.05, WindowWidth * 0.9, WindowHeight * 0.2
SubForm2.Move WindowWidth * 0.05, WindowHeight * 0.25, WindowWidth * 0.9, WindowHeight * 0.65
So this creates a small header section (SubForm1) on the form where I can select the criteria for the errors I want to see (data range, which team committed the error, etc) and then I can view the errors in the much larger section below the header (SubForm2) that holds the datasheet with the results.
I can propogate events up to the main form from the ErrorCriteria and ErrorResults forms that are now bound to the subform controls. That will help me to use the basic MVC design pattern for VBA described here. I can treat the main form as the view, even though parts of that view are buried in subform controls. The controller only has to know about that one view.
My problem comes when the user selects a new "screen" from the dropdown menu. I think it would be nice to just re-purpose the subform controls, like so:
SubForm1.SourceObject = "Form.WarehouseCriteria"
SubForm2.SourceObject = "Form.InventoryResults"
And then just move/resize those subforms to the appropriate layout for the "Inventory" screen.
This approach seems to make the user interface design cleaner in my mind because you basically only ever have to deal with one main form that acts as a template and then you plug in the values (the SourceObject properties) into that template.
But each time we change the "screen", we have a totally different "Model" behind the scenes and a new "View" too according to the MVC design pattern. I wonder if that would clutter up the MVC VBA code behind the scenes, or if the VBA code itself could be modularized too (possibly using Interfaces) to make it just as adaptable as the user interface.
What is the cleanest way to do this from both a User Interface perspective, and from a VBA perspective. Use one main form as template where other forms could be swapped in and out as subforms, or just close the current form and open a new form when the user selects a new "screen" from the dropdown menu.
Below is a brief description of one way to 'repurpose' or reformat a form for several uses. Re your question of changing the VBA code, a simple solution would be to check a label value or some value you set in the control, then call the appropriate VBA subroutine.
We had over 100 reports available, each with their own selection criteria/options and we did not want to create a unique filter form for every report. The solution was to identify the selection options available by report, identify the logical order of those options, then create a table that would present the options to the user.
First, we created the table: ctlReportOptions (PK = ID, ReportName, OptionOrder)
Fields: ID (Int), ReportName (text), OptionOrder (Int), ControlName (text), ControlTop (Int), ControlLeft (Int), SkipLabel (Y/N), ControlRecordsourc(text)
Note 1: ID is not an AutoNumber.
Next we populated with records that would define the view the user would see.
Note 2: Using an ID of zero, we created records for EVERY field on the report so we could always redraw for the developers.
Then we created the form and placed controls for every possible filter.
We set the 'Default Value' property to be used as our default.
Some of the controls:
ComboBox to select the report name. Add code for Change event as follows:
Private Sub cboChooseReport_Change()
Dim strSQL As String
Dim rs As ADODB.recordSet
Dim i As Integer
Dim iTop As Integer
Dim iLeft As Integer
Dim iLblTop As Integer
Dim iLblLeft As Integer
Dim iLblWidth As Integer
Dim iTab As Integer
Dim strLabel As String
On Error GoTo Error_Trap
' Select only optional controls (ID <> 0); skip cotrols always present.
strSQL = "SELECT ctlRptOpt.ControlName, 'lbl' & Mid([ControlName],4,99) AS LabelName, SkipLabel " & _
"From ctlRptOpt WHERE (((ctlRptOpt.ID)<>0)) " & _
"GROUP BY ctlRptOpt.ControlName, 'lbl' & Mid([ControlName],4,99), SkipLabel;"
Set rs = New ADODB.recordSet
rs.Open strSQL, CurrentProject.Connection, adOpenDynamic
Do While Not rs.EOF
Me(rs!ControlName).Visible = False ' Hide control
If rs!skiplabel = False Then ' Hide Label if necessary
Me(rs!LabelName).Visible = False
End If
rs.MoveNext
Loop
rs.Close
iTop = 0
iTab = 0
' Get list of controls used by this report; order by desired sequence.
strSQL = "select * from ctlRptOpt " & _
"where [ID] = " & Me.cboChooseReport.Column(3) & _
" order by OptionOrder;"
Set rs = New ADODB.recordSet
rs.Open strSQL, CurrentProject.Connection, adOpenDynamic
If rs.EOF Then ' No options needed
Me.cmdShowQuery.Visible = True
Me.lblReportCriteria.Visible = False
Me.cmdShowQuery.left = 2000
Me.cmdShowQuery.top = 1500
Me.cmdShowQuery.TabIndex = 1
Me.cmdReset.Visible = False
rs.Close
Set rs = Nothing
GoTo Proc_Exit ' Exit
End If
' Setup the display of controls.
Me.lblReportCriteria.Visible = True
Do While Not rs.EOF
If rs!skiplabel = False Then
strLabel = "lbl" & Mid(rs!ControlName, 4)
iLblWidth = Me.Controls(strLabel).Width
Me(strLabel).top = rs!ControlTop
Me(strLabel).left = rs!ControlLeft - (Me(strLabel).Width + 50)
Me(strLabel).Visible = True
End If
iTab = iTab + 1 ' Set new Tab Order for the controls
Me(rs!ControlName).top = rs!ControlTop
Me(rs!ControlName).left = rs!ControlLeft
Me(rs!ControlName).Visible = True
If left(rs!ControlName, 3) <> "lbl" Then
Me(rs!ControlName).TabIndex = iTab
End If
If Me(rs!ControlName).top >= iTop Then
iTop = rs!ControlTop + Me(rs!ControlName).Height ' Save last one
End If
' If not a label and not a 'cmd', it's a filter! Set a default.
If left(rs!ControlName, 3) <> "lbl" And left(rs!ControlName, 3) <> "cmd" Then
If Me(rs!ControlName).DefaultValue = "=""*""" Then
' Me(rs!ControlName) = "*"
ElseIf left(Me(rs!ControlName).DefaultValue, 2) = "=#" And right(Me(rs!ControlName).DefaultValue, 1) = "#" Then
i = Len(Me(rs!ControlName).DefaultValue)
' Me(rs!ControlName) = Mid(Me(rs!ControlName).DefaultValue, 3, i - 3)
ElseIf Me(rs!ControlName).DefaultValue = "True" Then
' Me(rs!ControlName) = True
ElseIf Me(rs!ControlName).DefaultValue = "False" Then
' Me(rs!ControlName) = False
End If
Else
If Me(rs!ControlName).top + Me(rs!ControlName).Height >= iTop Then
iTop = rs!ControlTop + Me(rs!ControlName).Height ' Save last one
End If
End If
rs.MoveNext
Loop
rs.Close
Set rs = Nothing
If Me.cboChooseReport.Column(1) <> "rptInventoryByDate" Then ' It's special
Me.cmdShowQuery.Visible = True
Me.cmdShowQuery.left = 2000
Me.cmdShowQuery.top = iTop + 300
iTab = iTab + 1
Me.cmdShowQuery.TabIndex = iTab
Else
Me.cmdShowQuery.Visible = False
End If
Me.cmdReset.Visible = True
Me.cmdReset.left = 5000
Me.cmdReset.top = iTop + 300
Me.cmdReset.TabIndex = iTab + 1
Proc_Exit:
Exit Sub
Error_Trap:
Err.Source = "Form_frmReportChooser: cboChooseReport_Change at Line: " & Erl
DocAndShowError ' Save error to database for analysis, then display to user.
Resume Proc_Exit ' Exit code.
Resume Next ' All resumption if debugging.
Resume
End Sub
lblReportCriteria: We displayed the final set of filters so when users complained of nothing showing on the report, we asked them to send us a screen print. We also passed this text to the report and it was printed as a footer on the last page.
cmdReset: Reset all controls back to their default values.
cmdShowQuery: Executes the running of the report
Private Sub cmdShowQuery_Click()
Dim qdfDelReport101 As ADODB.Command
Dim qdfAppReport101 As ADODB.Command
Dim qdfDelReport102 As ADODB.Command
Dim qdfAppReport102 As ADODB.Command
Dim qryBase As ADODB.Command
Dim strQueryName As String
Dim strAny_Open_Reports As String
Dim strOpen_Report As String
Dim qdfVendorsInfo As ADODB.Command
Dim rsVendorName As ADODB.recordSet
Dim strVendorName As String
Dim rsrpqFormVendorsInfo As ADODB.recordSet
On Error GoTo Error_Trap
If Not IsNull(Me.cboChooseReport.value) And Me.cboChooseReport.value <> " " Then
strAny_Open_Reports = Any_Open_Reports()
If Len(strAny_Open_Reports) = 0 Then
If Me.cboChooseReport.value = "rptAAA" Then
BuildReportCriteria '
If Me.chkBankBal = True Then
DoCmd.OpenReport "rptAAA_Opt1", acViewPreview
Else
DoCmd.OpenReport "rptAAA_Opt2", acViewPreview
End If
ElseIf Me.cboChooseReport.value = "rptBBB" Then
If IsNull(Me.txtFromDate) Or Not IsDate(Me.txtFromDate) Then
MsgBox "You must enter a valid From Date", vbOKOnly, "Invalid Date"
Exit Sub
End If
If IsNull(Me.txtToDate) Or Not IsDate(Me.txtToDate) Then
MsgBox "You must enter a valid To Date", vbOKOnly, "Invalid Date"
Exit Sub
End If
Me.txtStartDate = Me.txtFromDate
Me.txtEndDate = Me.txtToDate
DoCmd.OpenReport Me.cboChooseReport.value, acViewPreview
ElseIf Me.cboChooseReport.value = "rptCCC" Then
If Me.txtVendorName = "*" Then
gvstr_VendorName = "*"
Else
Set rsVendorName = New ADODB.recordSet
rsVendorName.Open "selVendorName", gv_DBS_Local, adOpenDynamic
Set qdfVendorsInfo = New ADODB.Command
qdfVendorsInfo.ActiveConnection = gv_DBS_SQLServer
qdfVendorsInfo.CommandText = ("qryVendorsInfo")
qdfVendorsInfo.CommandType = adCmdStoredProc
strVendorName = rsVendorName("VendorName")
gvstr_VendorName = strVendorName
End If
DoCmd.OpenReport "rptFormVendorReport", acViewPreview
Else
BuildReportCriteria
If Me.cboChooseReport.value = "rptXXXXXX" Then
ElseIf Me.cboChooseReport.value = "rptyyyy" Then
On Error Resume Next ' All resumption if debugging.
DoCmd.DeleteObject acTable, "temp_xxxx"
On Error GoTo Error_Trap
Set qryBase = New ADODB.Command
qryBase.ActiveConnection = gv_DBS_Local
qryBase.CommandText = ("mtseldata...")
qryBase.CommandType = adCmdStoredProc
qryBase.Execute
End If
DoCmd.Hourglass False
DoCmd.OpenReport Me.cboChooseReport.value, acViewPreview
End If
Else
MsgBox "You cannot open this form/report because you already have a form/report(s) open: " & _
vbCrLf & strAny_Open_Reports & _
vbCrLf & "Please close the open form/report(s) before continuing."
strOpen_Report = Open_Report
DoCmd.SelectObject acReport, strOpen_Report
DoCmd.ShowToolbar "tbForPost"
End If
Else
MsgBox "Please Choose Report", vbExclamation, "Choose Report"
End If
Exit Sub
Error_Trap:
Err.Source = "Form_frmReportChooser: cmdShowQuery_Click - Report: " & Nz(Me.cboChooseReport.value) & " at Line: " & Erl
If Err.Number = 2501 Then ' MsgBox "You chose not to open this report.", vbOKOnly, "Report cancelled"
Exit Sub
ElseIf Err.Number = 0 Or Err.Number = 7874 Then
Resume Next ' All resumption if debugging.
ElseIf Err.Number = 3146 Then ' ODBC -- call failed -- can have multiple errors
Dim errLoop As Error
Dim strError As String
Dim Errs1 As Errors
' Enumerate Errors collection and display properties of each Error object.
i = 1
Set Errs1 = gv_DBS_SQLServer.Errors
Err.Description = Err.Description & "; Err.Count = " & gv_DBS_SQLServer.Errors.Count & "; "
For Each errLoop In Errs1
With errLoop
Err.Description = Err.Description & "Error #" & i & ":" & " ADO Error#" & .Number & _
" Description= " & .Description
i = i + 1
End With
Next
End If
DocAndShowError ' Save error to database for analysis, then display to user.
Exit Sub
Resume Next ' All resumption if debugging.
Resume
End Sub
Function to build a string showing all of the selection criteria:
Function BuildReportCriteria()
Dim frmMe As Form
Dim ctlEach As Control
Dim strCriteria As String
Dim prp As Property
Dim strSQL As String
Dim rs As ADODB.recordSet
On Error GoTo Error_Trap
strSQL = "select * from ctlRptOpt " & _
"where ID = " & Me.cboChooseReport.Column(3) & _
" order by OptionOrder;"
Set rs = New ADODB.recordSet
rs.Open strSQL, CurrentProject.Connection, adOpenDynamic
If rs.EOF Then
strCriteria = " Report Criteria: None"
Else
strCriteria = " Report Criteria: "
End If
Do While Not rs.EOF
Set ctlEach = Me.Controls(rs!ControlName)
If ctlEach.ControlType = acTextBox Or ctlEach.ControlType = acComboBox Then
If ctlEach.value <> "*" And ctlEach.Name <> "cboChooseReport" And ctlEach.Name <> "cboLocCountry" Then
strCriteria = strCriteria & ctlEach.Tag & " = " & ctlEach.value & " , "
End If
End If
rs.MoveNext
Loop
rs.Close
Set rs = Nothing
If Me.chkOblBal = -1 Then
strCriteria = strCriteria & "Non-zero balances only = Yes"
Else
'return string with all choosen criteria and remove last " , " from the end of string
strCriteria = left$(strCriteria, Len(strCriteria) - 3)
End If
fvstr_ReportCriteria = strCriteria
Set ctlEach = Nothing
Exit Function
Error_Trap:
If Err.Number = 2447 Then
Resume Next ' All resumption if debugging.
End If
Err.Source = "Form_frmReportChooser: BuildReportCriteria at Line: " & Erl
DocAndShowError ' Save error to database for analysis, then display to user.
Exit Function
Resume Next ' All resumption if debugging.
End Function
Finally, each report had it's own query that would filter based on the values in the controls on this form.
Hope this helps. If you are curious about any of the weird things you see, let me know. (i.e. we always used line numbers in the code (I deleted before posting) that allowed us to identify exact line where code fails)

Creating a Calendar in Access 2010

I have been desperately trying to find a way to make a calendar in Access. I know it can be done, as I've seen wonderful examples, but I don't know how. (Also, my VB knowledge is minimal.)
Basically, I want the calendar to show a range of dates of when a program (we call them capsules) has been checked out, and when it will be returned.
DateReserve - the Date a capsule has been reserved
DateReturn - the Date when the capsule needs to be returned.
For example, if Capsule A is reserved on 6/1/2014 and will return 6/14/2014, I want the calendar to visually show that Capsule A will be unavailable during this time period. That way, we don't accidentally double-book a capsule.
Through one of my many google searches, I did find VB code that pulls up a very nice looking calendar. I just can't get the code right to visually show what dates a capsule will be unavailable.
Below is one of the sections of code I can't get to work right:
Private Sub OpenContinuousForm(ctlName As String)
Dim ctlValue As Integer
Dim DaysOfMonth As Long
Dim DateReturn As Date
Dim DateShipOut As Date
Dim DateRangeForProgram As String
DateRangeForProgram = (DateDiff("n", [DateReturn], [DateShipOut]))
On Error GoTo ErrorHandler
ctlValue = Me.Controls(ctlName).Tag
DaysOfMonth = MyArray(ctlValue - 1, 0)
DoCmd.OpenForm "frmCapsulesSchedule", acNormal, , [DateRangeForProgram] = DaysOfMonth
ExitSub:
Exit Sub
ErrorHandler:
MsgBox "DATE SHIP OUT FAILED.", , "Error!!!"
Resume ExitSub
End Sub
Please let me know if you need further information from me.
Here is the code I used for the calendar; Anywhere you see 'Teachers,' 'Schools,' or 'Capsules' would be where you'd put your own information:
Option Compare Database
Option Explicit
Private intYear As Integer
Private intMonth As Integer
Private lngFirstDayOfMonth As Long
Private intLastDayOfLastMonth As Integer
Private intFirstWeekday As Integer
Private intDaysInMonth As Integer
Private strFormReference As String
Private MyArray() As Variant
Private Sub cboMonth_Click()
On Error GoTo Errorhandler
Call Main
ExitSub:
Exit Sub
Errorhandler:
MsgBox "There has been an error. Please reload the form.", , "Error"
Resume ExitSub
End Sub
Private Sub cboYear_AfterUpdate()
On Error GoTo Errorhandler
Call Main
ExitSub:
Exit Sub
Errorhandler:
MsgBox "There has been an error. Please reload the form.", , "Error"
Resume ExitSub
End Sub
Private Sub Form_Load()
On Error GoTo Errorhandler
'Set the month and date to this current month and date
With Me
.cboMonth = Month(Date)
.cboYear = Year(Date)
End With
Call Main
ExitSub:
Exit Sub
Errorhandler:
MsgBox "There has been an error. Please reload the form.", , "Error"
Resume ExitSub
End Sub
Public Sub InitVariables()
On Error GoTo Errorhandler
intYear = Me.cboYear
intMonth = Me.cboMonth
lngFirstDayOfMonth = CLng(DateSerial(intYear, intMonth, 1))
intFirstWeekday = getFirstWeekday(lngFirstDayOfMonth)
intDaysInMonth = getDaysInMonth(lngFirstDayOfMonth)
'This is where you add the reference for the form
'It is used in case we wish to add the module to a subform
ExitSub:
Exit Sub
Errorhandler:
MsgBox "There has been an error. Please reload the form.", , "Error"
Resume ExitSub
End Sub
Public Sub Main()
On Error GoTo Errorhandler
Call InitVariables
Call InitArray
Call LoadArray
Call PrintArray
ExitSub:
Exit Sub
Errorhandler:
MsgBox "There has been an error. Please reload the form.", , "Error"
Resume ExitSub
End Sub
Public Sub InitArray()
'First column will add all dates of the array
'Second column will add visible property
'Third column will hold the string variable
Dim i As Integer
On Error GoTo Errorhandler
ReDim MyArray(0 To 41, 0 To 3)
For i = 0 To 41
MyArray(i, 0) = lngFirstDayOfMonth + 1 - intFirstWeekday + i
If Month(MyArray(i, 0)) = intMonth Then
MyArray(i, 1) = True
'This works out the days of the month
MyArray(i, 2) = i + 2 - intFirstWeekday & vbNewLine
Else
MyArray(i, 1) = False
End If
Next i
ExitSub:
Exit Sub
Errorhandler:
MsgBox "There has been an error. Please reload the form.", , "Error"
Resume ExitSub
End Sub
Public Sub LoadArray()
'This sub loads an array with the relevant variables from a query
Dim db As Database
Dim rs As Recordset
Dim rsFiltered As Recordset
Dim strQuery As String
Dim i As Integer
On Error GoTo ErrorHandler1
strQuery = "Select * FROM [qryDatesYearsCapsules2]"
Set db = CurrentDb
Set rs = db.OpenRecordset(strQuery)
With rs
If Not rs.BOF And Not rs.EOF Then
'Ensures the recordset contains records
On Error GoTo ErrorHandler2
For i = 0 To UBound(MyArray)
'Will loop through the array and use dates to filter down the query
'It firsts checks that the second column has true for its visible property
If MyArray(i, 1) = True Then
.Filter = "[NewDate]=" & MyArray(i, 0)
'To filter you must open a secondary recordset and
'Use that as the basis for a query
'This makes sense as you are building a query on a query
Set rsFiltered = .OpenRecordset
If Not rsFiltered.BOF And Not rsFiltered.EOF Then
'If the recordset is not empty then you are able
'to extract the text from the values provided
Do While Not rsFiltered.EOF = True
MyArray(i, 2) = MyArray(i, 2) & rsFiltered!CapsuleSet
' MyArray(i, 2) = MyArray(i, 2) & vbNewLine & rsFiltered!Teacher
MyArray(i, 2) = MyArray(i, 2) & vbNewLine & rsFiltered!School
' MyArray(i, 2) = MyArray(i, 2) & " - " & rsFiltered!NewDate
MyArray(i, 2) = MyArray(i, 2) & vbNewLine & vbNewLine
rsFiltered.MoveNext
Loop
End If
End If
Next i
End If
.Close
End With
ExitSub:
Set db = Nothing
Set rs = Nothing
Exit Sub
ErrorHandler1:
MsgBox "There has been an error. Please reload the form.", , "Error"
Resume ExitSub
ErrorHandler2:
MsgBox "There has been an error. Please reload the form.", , "Error"
Resume ExitSub
End Sub
Public Sub PrintArray()
Dim strTextBox As String
Dim i As Integer
On Error GoTo Errorhandler
For i = 0 To 41
strTextBox = "txt" & CStr(i + 1)
With Me
Controls(strTextBox) = ""
Controls(strTextBox).tag = i + 1
Controls(strTextBox) = MyArray(i, 2)
'Debug.Print strTextBox
'MyArray(i, 2)
End With
Next i
ExitSub:
Exit Sub
Errorhandler:
MsgBox "There has been an error. Please reload the form.", , "Error"
Resume ExitSub
End Sub
Private Sub OpenContinuousForm(ctlName As String)
Dim ctlValue As Integer
Dim DayOfMonth As Long
On Error GoTo Errorhandler
ctlValue = Me.Controls(ctlName).tag
DayOfMonth = MyArray(ctlValue - 1, 0)
DoCmd.OpenForm "frmClassDataEntry", acNormal, , "[NewDate]=" & DayOfMonth, , acDialog
ExitSub:
Exit Sub
Errorhandler:
MsgBox "There has been an error. Please reload the form.", , "Error"
Resume ExitSub
End Sub
Private Sub txt1_Click()
On Error GoTo Errorhandler
If Me.ActiveControl.Text <> "" Then
Call OpenContinuousForm(Me.ActiveControl.Name)
End If
ExitSub:
Exit Sub
Errorhandler:
MsgBox "There has been an error. Please reload form."
Resume ExitSub
End Sub
'Repeat the code for txt1_Click() all the ways to txt42_Click()
Private Sub Format()
Dim ctl As Control
Dim lngBackColor As Long
For Each ctl In Me.Detail.Controls
If DCount("*", "lstCapsules", "[Capsule]='" & ctl.Value & "'") = 0 Then
lngBackColor = 16777215
Else
lngBackColor = DLookup("Background", "lstCapsules", "[Capsule]='" & ctl.Value & "'")
End If
ctl.BackColor = lngBackColor
Next ctl
Set ctl = Nothing
End Sub
I also have a module called modFunctions:
Option Compare Database
Option Explicit
Public Function getFirstWeekday(lngFirstDayOfMonth As Long) As Integer
On Error GoTo Errorhandler
getFirstWeekday = -1
getFirstWeekday = Weekday(lngFirstDayOfMonth, vbMonday)
ExitFunction:
Exit Function
Errorhandler:
getFirstWeekday = 0
MsgBox "There has been an error. Please reload the form.", , "Error"
Resume ExitFunction
End Function
Public Function getDaysInMonth(lngFirstDayOfMonth As Long) As Integer
On Error GoTo Errorhandler
getDaysInMonth = -1
getDaysInMonth = DateDiff("d", lngFirstDayOfMonth, DateAdd("m", 1, lngFirstDayOfMonth))
ExitFunction:
Exit Function
Errorhandler:
getDaysInMonth = 0
MsgBox "Something is wrong with the DATES!.", , "Date Error"
Resume ExitFunction
End Function
There is a very useful youtube video I came across by Access All In One. Here is a link to the database used in the example
Your syntax in the Where condition of the openform command is incorrect.
It should be "[DateRangeForProgram]=" & DaysOfMonth, if the field your using to filter the form's recordsource is [DateRangeForProgram].
Also, if you're trying to open the form to multiple days, you should likely be using the Between operator. The datediff function's first argument specifies an interval, and your interval is minutes.
You should post the rest of the code so the entire scenario is clear.

Is there a faster alternative to DLookup?

I'm using DLookup to search for a field in a table. It runs correctly, but is slow. Is there anything I can do to speed it up?
Here's my existing code:
Private Sub cmdLogin_Click()
strUserLevel = ""
If IsNull(Me.cmbUserName) Or Me.cmbUserName = "" Then
MsgBox "You must enter a User Name.", vbOKOnly, "Required Data"
Me.cmbUserName.SetFocus
Exit Sub
End If
If IsNull(Me.txtPassword) Or Me.txtPassword = "" Then
MsgBox "You must enter a Password.", vbOKOnly, "Required Data"
Me.txtPassword.SetFocus
Exit Sub
End If
'strUserName = cmbUserName.Value
If Me.txtPassword.Value = DLookup("Password", "tableUser", "[lngEmpID]=" & Me.cmbUserName.Value) Then
lngMyEmpID = Me.cmbUserName.Value
strUserLevel = DLookup("Department", "tableUser", "[lngEmpID]=" & Me.cmbUserName.Value)
strUserName = DLookup("User_Name", "tableUser", "[lngEmpID]=" & Me.cmbUserName.Value)
boolInventoryMDL = DLookup("Inventory", "tableDepartment", "[Department]=""" & strUserLevel & """")
boolDispositionMDL = DLookup("Disposition", "tableDepartment", "[Department]=""" & strUserLevel & """")
boolReviewCloseMDL = DLookup("Review", "tableDepartment", "[Department]=""" & strUserLevel & """")
boolAdministratorMDL = DLookup("Administrator", "tableDepartment", "[Department]=""" & strUserLevel & """")
boolUserListMDL = DLookup("UserList", "tableDepartment", "[Department]=""" & strUserLevel & """")
boolUserLevelMDL = DLookup("UserLevel", "tableDepartment", "[Department]=""" & strUserLevel & """")
If strUserLevel = "Superuser" Then
MsgBox "Welcome back Superuser! You can access all the modules here..", vbOKOnly, "Caution"
Else
MsgBox "Welcome! Login Success!", vbOKOnly, "Login Page"
End If
DoCmd.Close acForm, "frmLogin", acSaveNo
DoCmd.OpenForm "frmModule"
Else
MsgBox "Password Invalid. Please Try Again", vbOKOnly, "Invalid Entry!"
Me.txtPassword.Value = ""
Me.txtPassword.SetFocus
End If
End Sub
I don't believe the problem is due to inherent slowness of DLookup. Rather the problem is that the code uses so many of them.
Open one recordset based on a query of tableUser and take the values you need from that recordset. Then open a second recordset from a query of tableDepartment and get your remaining values.
Dim db As DAO.database
Dim qdf As DAO.QueryDef
Dim rs As DAO.Recordset
Dim strSelect As String
strSelect = "SELECT u.Password, u.Department, u.User_Name" & vbCrLf & _
"FROM tableUser AS u WHERE u.lngEmpID = [which_EmpId];"
Set db = CurrentDb
Set qdf = db.CreateQueryDef(vbNullString, strSelect)
qdf.Parameters("which_EmpId") = Me.cmbUserName
Set rs = qdf.OpenRecordset(dbOpenSnapshot)
If Not rs.EOF Then
If rs![Password] = Me.txtPassword Then
strUserLevel = rs!Department
strUserName = rs!User_Name
rs.Close
' open another recordset from a query of tableDepartment
' to retrieve your bool????? values
End If
End If
In that abbreviated sample, I used a temporary QueryDef for the parameterized SELECT query. However you would be better of to save that SQL as a named query, perhaps qryFetchUserData. Then at run time, instead of recreating the query each time, you could simply open the saved query.
Set qdf = db.QueryDefs("qryFetchUserData")
For optimum performance, you should add indexes on tableUser.lngEmpID and tableDepartment.Department if they're not already indexed.