Check for existing date

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • twinnyfo
    Recognized Expert Moderator Specialist
    • Nov 2011
    • 3653

    #31
    First, I think you are getting closer to understanding a few things. So, anything new that you learn and can put into practice is a good thing, right?

    Let's begin by making a new form for signing in. You can still keep the old one that works, but I want to work through some concepts with you that should help in the long run.

    Next, humor me by adding two fields to tbl_master:
    Code:
    [B][U]Field[/U][/B]     [B][U]Type[/U][/B]         [B][U]Format[/U][/B]
    SignIn    Date/Time    General Date
    SignOut   Date/Time    General Date
    I ask this because I want to show you how to streamline your data, and thus, your code.

    Now, you've described what your sign in form "looks" like, so we will go with what you have. So, on this new form create those same eight buttons (one for sign in and one for sign out for each employee). However--and this is very important--you will want to give them very specific names. I can only assume that you have the names of your Employees in Your Table? You must use the name of the employee as found in your table in the name of your command buttons. So, your sign in buttons will all be named cmdSignIn[Employee Name]; your sign out buttons will all be named cmdSignOut[Employee Name]. Example: cmdSignInJohn Smith; cmdSignOutEggbe rt Schmuckatelli, etc. Make sense, so far? Just make sure none of your employees have any special characters like apostrophes or commas in them--if so, change their names in the DB.

    Also add a Close button so you can close the form, because there is some testing we have to do.

    Bind the form to tbl_master, as before. Remember, when the form first opens, we don't want to have any records available for editing (and we will get to more later on), but we will filter the form based upon the Employee Name, but on one that doesn't produce any records. So, the VBA behind your form, to begin with will look like this:
    Code:
    Option Compare Database
    Option Explicit
    
    Private Sub Form_Open(Cancel As Integer)
    On Error GoTo EH
    
        Me.Filter = "Employee = ''"
        Me.FilterOn = True
    
        Exit Sub
    EH:
        MsgBox "There was an error initializing the Form!  " & _
            "Please contact your Database Administrator.", _
            vbCritical, "WARNING!"
        Exit Sub
    End Sub
    Do you see why we do this? We Filter by something that returns no records, but because we have to text boxes associated with any fields in the table, this is immaterial.

    So, remember that I said we break this down into smaller problems? Let's start with the problem of enabling/disabling the sign in/out buttons. You will now see why we have given these command buttons such strange names.

    At this point, you could write code that checks the status of each employee and then enables/disables buttons for each employee. However, doing such would be redundant (you would be duplicating code that you can consolidate easily). So, how do we do that?

    We will create a function that can be called multiple times that will perform this function for you. Granted, you will have to call this function for each employee you have, and in a perfect world, the DB would go out and find your employees, but, since you have a small operation, for now, this will suffice.

    However, if you think about this in greater depth, you may start to ask yourself a question.... What I really want is a "real-time" assessment of the employee's sign in/out status. So, wouldn't I want to check this status anytime anyone clicks a button?

    Right you are! And, if you break this into even smaller pieces, what we are doing is not just checking the status of an employee, we are checking the status of each employee. So, what you want is two functions: One function will check the status of an employee; the other function asks that function to check the status of each employee. Let me show you how that is done.....

    Remember our Boolean variables from Post #17?
    Code:
    Dim fCheckIn  As Boolean
    Dim fCheckOut As Boolean
    Well, rather than declaring them within a procedure, lets declare them in the Form. We do this by placing their declaration above the other procedures, but below the first two lines of code:

    Code:
    Option Compare Database
    Option Explicit
    
    Private fCheckIn  As Boolean
    Private fCheckOut As Boolean
    Rather than using the Dim statement, we use the Private statement, which means that these variables are available for use anywhere in the VBA module--not just one particular procedure. Since we will be using these variables throughout this form, this is why we do it.

    Now, we need to check the status of each of our employees. Let's create a procedure called CheckStatus, that will send the list of employee names to your function (which is yet un-built) that will check their status and determine what to do with each button. Conceptually, all you need this tiny procedure to do is check the status of each employee by name. Thus, when you add employees (or remove employees), this is the only VBA you need to change (besides adding/removing buttons). This is all you need:
    Code:
    Private Sub CheckStatus()
    On Error GoTo EH
    
        CheckEmployee "Joe Smith"
        CheckEmployee "Eggbert Schmuckatelli"
        CheckEmployee "Harold Umptyfratz"
    
        Exit Sub
    EH:
        MsgBox "There was an error checking the status!  " & _
            "Please contact your Database Administrator.", _ 
            vbCritical, "WARNING!"
        Exit Sub
    End Sub
    Can you see how this is more efficient (conceptually) already??

    But you might say, "Hey, I don't have a Function named CheckEmpoyee yet!" That's OK--we'll make that right now! Look closely at the VBA below:
    Code:
    Private Function CheckEmployee(Employee As String)
    On Error GoTo EH
    
        fCheckIn = Nz(DLookup("[SignIn]", "tbl_Master", _
            "[Employee] = '" & Employee & "' " & _
            "AND Format([SignIn], 'yyyy-mm-dd') = '" & _
            Format(Date, "yyyy-mm-dd") & "'"), False)
     
        fCheckOut = Nz(DLookup("[SignOut]", "tbl_Master", _
            "[Employee] = '" & Employee & "' " & _
            "AND Format([SignOut], 'yyyy-mm-dd') = '" & _
            Format(Date, "yyyy-mm-dd") & "'"), False)
    
        Me("cmdSignIn" & Employee).Enabled = Not fCheckIn
        Me("cmdSignOut" & Employee).Enabled = Not fCheckOut
    
        Exit Function
    EH:
        MsgBox "There was an error checking the status!  " & _
            "Please contact your Database Administrator.", _ 
            vbCritical, "WARNING!"
        Exit Function
    End Function
    Remember in the previous block we were sending the Employee name to the function in question. That function takes that employee name, checks their status in tbl_master. Also remember that tbl_master has two new fields, SignIn and SignOut, which are date/Time fields, and hold the date and time, not just the date. But, by using the Format() function, we are converting those date/times into text strings which represent the date only, and compare it to today's date, in the same format.

    Then, a neat little trick I learned from Microsoft many years back, notice your command buttons can be referenced with a combination of text and variable: Me("cmdSignIn" & Employee). This is why you needed to name your command buttons so diligently! If someone has checked in today, the sign in button is disabled. If someone has checked out today, the sign out button is disabled.

    Now, just add this line to your OnOpen event we created earlier:
    Code:
    CheckStatus
    You can put that right after the filter statements. This will check the status of your employees!

    Remember: small chunks at a time. Build this slowly, and work through understanding what is going on before you go to any future steps. Let me know how this works. Practice adding some sample data in tbl_master, and let me know what the results are. any errors or surprising results, we can work through tomorrow.

    Comment

    • didacticone
      Contributor
      • Oct 2008
      • 266

      #32
      Sorry i came down with a bug yesterday and was away... this was a nice gift to return to. Thank you for this. I am going to work on it today... I will not be back until Monday, so that gives me plenty of time lol... if i run into any initial issues i will let you know. I did have one question... you said " I can only assume that you have the names of your Employees in Your Table?" What do you mean by this? Their names were getting entered only when they signed in... they werent field names... so just a little confused there... thanks again!

      Comment

      • twinnyfo
        Recognized Expert Moderator Specialist
        • Nov 2011
        • 3653

        #33
        In a properly structured DB (see this Article on DB Normalization), you would have a Table with just your Employess listed. Example:

        tblEmployees
        Code:
        [B][U]ID[/U][/B]   [B][U]EmplyeeName[/U][/B]   [B][U]EmployeeAddress[/U][/B]  ... etc.
        1    Joe Schmoe    123 Main St.
        2    Mel Function  321 What Rd.
        3    Risky Walrus  987 Over Dr.
        Then, rather than saving the Employee's Name to any related tables, you only save the index. This saves on DB resources and helps with look ups, combo boxes and everything else.

        Based upon your description, this is not how you are listing your employees, but you save the actual name of the employee in your table. As long as the employee's name is exactly the same, every single time, you are safe, but any time a name might get entered incorrectly, you will have issues.

        This is why I would always recommend to have the employee select their name from a combo box, which would then do initial determinations on whether they have signed in/out. Then, rather than having to hard code names, you just have a reference to the employee index from the combo box. Adding an employee (and having a fully functional DB) is as simple as adding a name to the employees table. I know you are not looking to expand, but what if someone quits and you have to hire, not an additional employee, but a different employee? I am trying to save you from headaches with such issues.

        You may say, "Well, it's easy to just reprogram these three lines of code here and rename some objects here--it won't take but 15 minutes to do these updates." True, but we musn't be satisfied with a project that works just because it works. We should think about proper project development and adhering to good, sound, tried and true development principles.

        Anecdotally, I am completely self-taught. However, everything I learned, I learned the hard way. I kept doing things the wrong way, but kept doing them that way "because they worked". After years of struggling and scratching my head, I started looking at my DB structure and code and said, "Hey, what if I do this...? I can streamline this section by doing it another way!" So, over time, I gradually ironed out very many of my "wrong" ways of doing things for the "right" way of doing things. Having come upon certain road blocks and hurdles, I came across Bytes. Lo and behold, many of my "tried-and-true-practices-that-I-learned-the-hard-way" were actually long-established DB design and development paradigms universally accepted as best practices.

        Hmmphh!! Why didn't anyone tell me how to do this in the first place? I could have saved thousands of hours of re-work and many bottle of Tylenol!

        Folks on this forum must think I just keep harping on the same old things over and over again. I do--because I want to prevent others from going down the road of mediocrity with a project that "works". There are certain principles which, if known and understood, will allow you to go beyond your current level of proficiency and let you explore other areas of your craft.

        You may not see a "need" for that right now--but I guarantee you that sooner or later, those who have you creating the employee DB will eventually ask, "Hey! I was wondering if you could get the db to do...." And it doesn't matter what it is. I want you to have the confidence to be able to help your boss (or yourself, if you are the boss).

        Enjoy your weekend!

        Comment

        • didacticone
          Contributor
          • Oct 2008
          • 266

          #34
          OK, totally understood, and feel like that is my motto as well... "if it works, it works"... but i dont want that to be it... understanding the proper way is awesome and also like you said saves on the tylenol and typing redundant lines of code... OK so i actually do have a seperate table calles "tbl_employ ees" structured just like you showed except with just the names, no addresses or anything... how does this factor in? Also, bear with me because i haven't even read through your entire post yet, but what code would go behind the sign in and out buttons... would i just need
          Code:
          me.signin = now ()
          or do i need to add the name of the employee to the code? or because of the other table it is going to be referenced?

          Comment

          • twinnyfo
            Recognized Expert Moderator Specialist
            • Nov 2011
            • 3653

            #35
            OK so i actually do have a seperate table calles "tbl_employ ees" structured just like you showed except with just the names, no addresses or anything... how does this factor in?
            Does your table have an index for each employee (see post #33 above) or just the name?

            do i need to add the name of the employee to the code? or because of the other table it is going to be referenced?
            Let's figure out your table structure first. This will drive how we add the employee to tbl_master....

            Comment

            • didacticone
              Contributor
              • Oct 2008
              • 266

              #36
              The table just has the primary key (ID field) and the employee name

              Comment

              • twinnyfo
                Recognized Expert Moderator Specialist
                • Nov 2011
                • 3653

                #37
                And tbl_master uses the index? Or the text value for your Employee? Th9is will affect how we determine check in/out status from Post #31.

                Plus:
                How do you want your sing in form to work? Combo box with two buttons or 8 buttons?

                I don't want us going off the rails on a crazy train until we figure out for sure how you want it to look/feel.

                Comment

                • didacticone
                  Contributor
                  • Oct 2008
                  • 266

                  #38
                  i'll be honest im not familiar with using the index, so im going to assume it uses the text value for employee...

                  i would prefer the four names listed on my form (as they are now, just labels) with a sign in and out for each...

                  nice ozzy reference LOL... i think i have driven you off the rails already my friend... sorry and thanks!!!

                  Comment

                  • twinnyfo
                    Recognized Expert Moderator Specialist
                    • Nov 2011
                    • 3653

                    #39
                    i'll be honest im not familiar with using the index, so im going to assume it uses the text value for employee...
                    Then let's get you set up properly.

                    (Forgive me if you already know how to do this or have already done this, but I want to make sure it is done right.)
                    Open tbl_master in design view.

                    Add a field called "Employee2" - this is the field we will use for this experiment going forward. You can always change the original Employee field in the future, but we will work through this step-by-step.

                    Select Data Type of Lookup Wizard...

                    Select the radio button for "I want the lookup field to get the values from another table or query."

                    Click "Next >".

                    Select your Employees Table (whatever its name is). Click "Next >".

                    Click on the ID and the Employee Name (whatever your field names are), so that they are both in the right side pane of the window. Click "Next >".

                    Select the Sort order of your Employee Name. Click "Next >".

                    Make sure the "Hide key column (recommended)" check box is checked. Click "Next >".

                    Make sure the "Allow Multiple Values" check box is unchecked. Click "Finish".

                    Click "Yes" to save the table.

                    Open the table is datasheet view and examine your new field. It will be shown as a drop down list, from which you can select an employee. However, what is actually happening is that you are selecting the index for that employee. The size of the field is only as large as an integer.

                    So, now, this changes a few things from Post #31. Your Command Buttons, you must use the index of the employee as found in your employees table in the name of your command buttons. So, your sign in buttons will all be named cmdSignIn[Employee Index]; your sign out buttons will all be named cmdSignOut[Employee Index]. Example: cmdSignIn2; cmdSignOut6, etc. Does this make sense?

                    Then, some minor changes to our other code from that same post:

                    Code:
                    Private Sub CheckStatus()
                    On Error GoTo EH
                    
                        CheckEmployee 2
                        CheckEmployee 5
                        CheckEmployee 7
                    
                        Exit Sub
                    EH:
                        MsgBox "There was an error checking the status!  " & _
                            "Please contact your Database Administrator.", _ 
                            vbCritical, "WARNING!"
                        Exit Sub
                    End Sub
                    (of course you will add the employee index from your table) Do you understand why we made these changes?

                    And the other function:
                    Code:
                    Private Function CheckEmployee(Employee As Integer)
                    On Error GoTo EH
                    
                        fCheckIn = Nz(DLookup("[SignIn]", "tbl_Master", _
                            "[Employee] = " & Employee & " " & _
                            "AND Format([SignIn], 'yyyy-mm-dd') = '" & _
                            Format(Date, "yyyy-mm-dd") & "'"), False)
                     
                        fCheckOut = Nz(DLookup("[SignOut]", "tbl_Master", _
                            "[Employee] = " & Employee & " " & _
                            "AND Format([SignOut], 'yyyy-mm-dd') = '" & _
                            Format(Date, "yyyy-mm-dd") & "'"), False)
                    
                        Me("cmdSignIn" & Employee).Enabled = Not fCheckIn
                        Me("cmdSignOut" & Employee).Enabled = Not fCheckOut
                    
                        Exit Function
                    EH:
                        MsgBox "There was an error checking the status!  " & _
                            "Please contact your Database Administrator.", _ 
                            vbCritical, "WARNING!"
                        Exit Function
                    End Function
                    The only changes are that Employee (the value sent to the function) is a integer (you may have it in your table as a Long if it is an autonumber) and the removal of the single quotes in the DLookup() functions, because we are looking for numbers and not text strings. All else remains the same.

                    This is your assignment for the weekend!

                    Hope this hepps!

                    Comment

                    • didacticone
                      Contributor
                      • Oct 2008
                      • 266

                      #40
                      So following along with what you said I am stuck with some of the language... "However, what is actually happening is that you are selecting the index for that employee. The size of the field is only as large as an integer.

                      So, now, this changes a few things from Post #31. Your Command Buttons, you must use the index of the employee as found in your employees table in the name of your command buttons.


                      What is considered the index of the employee?

                      Also once this is answered, is the code for each button simply:

                      Code:
                      me.signin = now
                      ?

                      Comment

                      • twinnyfo
                        Recognized Expert Moderator Specialist
                        • Nov 2011
                        • 3653

                        #41
                        Also once this is answered, is the code for each button simply:

                        Code:
                        me.signin = now
                        Let's not get ahead of ourselves. We will get there. Small chunks, one step at a time.... Remember?

                        What is considered the index of the employee?
                        tblEmployees.ID is the index. It is the value that "represents " everything else in that particular record.

                        This might help you understand better. There are many things that could be associated with an employee: Name, Address, Birth Date, Favorite Color, left- or right-handed. All of this could go into one table concerning employees. The index, will represent all those attributes of each employee elsewhere in your DB.

                        Let say you are building a form that schedules employees. You have dates set aside, work periods on each day, etc. And you can add employees to each work period. Rather than typing each each employee's name (and taking up additional space with long strings), you use a drop down box which shows the employee's name, but stores the employee's index. Then, let say you want to see whether the employee in a particular work period had red hair, writes left-handed and lives in Hoboken, NJ. Well, you use the index to find the record that pertains to that employee. This is a foundational understanding of a relational database.

                        Hope this hepps!

                        Comment

                        • didacticone
                          Contributor
                          • Oct 2008
                          • 266

                          #42
                          Also when i try to open the form now im getting "type mismatch in expression" error.

                          Comment

                          • twinnyfo
                            Recognized Expert Moderator Specialist
                            • Nov 2011
                            • 3653

                            #43
                            Correction to the above:

                            Code:
                            Private Function CheckEmployee(Employee As Integer)
                            On Error GoTo EH
                             
                                fCheckIn = Nz(DLookup("[SignIn]", "tbl_Master", _
                                    "[Employee[highlight][B][I][U]2[/U][/I][/B][/highlight]] = " & Employee & " " & _
                                    "AND Format([SignIn], 'yyyy-mm-dd') = '" & _
                                    Format(Date, "yyyy-mm-dd") & "'"), False)
                             
                                fCheckOut = Nz(DLookup("[SignOut]", "tbl_Master", _
                                    "[Employee[highlight][B][I][U]2[/U][/I][/B][/highlight]] = " & Employee & " " & _
                                    "AND Format([SignOut], 'yyyy-mm-dd') = '" & _
                                    Format(Date, "yyyy-mm-dd") & "'"), False)
                             
                                Me("cmdSignIn" & Employee).Enabled = Not fCheckIn
                                Me("cmdSignOut" & Employee).Enabled = Not fCheckOut
                             
                                Exit Function
                            EH:
                                MsgBox "There was an error checking the status!  " & _
                                    "Please contact your Database Administrator.", _ 
                                    vbCritical, "WARNING!"
                                Exit Function
                            End Function

                            Comment

                            • Rabbit
                              Recognized Expert MVP
                              • Jan 2007
                              • 12517

                              #44
                              Anyone can sign in as anyone else? Seems like a security issue. What do you do about accidental logins?

                              Comment

                              • didacticone
                                Contributor
                                • Oct 2008
                                • 266

                                #45
                                Now i got enter parameter value... employee.value

                                Comment

                                Working...