0

I am using Access 2016 and building an in-house HR app for my team.

I have a Position Table, an Employee Table, a Position_Employee Table and a Staffing Table

Position Table
-------------
position_id autonumber
position_number
position_title
group_id FK
level_id FK

Employee Table
-------------
employee_id autonumber
last_name
first_name
dob

Position_Employee Table
------------- 
position_employee_id autonumber
start_date
end_date
is_indeterminate
is_current
position_id FK
employee_id FK



Staffing Table
-------------
staffing_id autonumber
reference_number
hr_confirmation
start_date
end_date
staffing_status_id FK
staffing_type_id FK
position_id FK
employee_id FK
hiring_manager_id FK

My logic is based on the position as more than one employee can occupy the same position.

The logic is the following:
- An Employee can have a indeterminate position
- An Employee can also have a determinate position while keeping their indeterminate position
- An Employee can only have a determinate position
- A Position can have an indeterminate Employee
- A Position can also have a determinate Employee while having an Indeterminate employee
- A Position can also have a determinate Employee and no Indeterminate employee (i.e vacant)
- The Staffing table is where the different staffing processes goes so an employee can be hired and put in a position as determinate, indeterminate and so on.

I was told not to use flag as it could become a nightmare to maintain later on so technically, in my table Position_Employee, I shouldn't have is_indeterminate, is_current.

What I want to do in pseudo-code is the following:

Trigger on Staffing table
If Insert in Staffing table
    If Staffing.staffing_status_id = 1  * staffing_stadus_id = 1 = Completed *
        Insert New position_employee_id in Position_Employee table
        position_employee.position_id = staffing.position_id
        position_employee.employee_id = staffing.employee_id
        position_employee.start_date = staffing.start_date
        position_employee.end_date = staffing.end_date
    If staffing_type = 1 *staffing_type = 1 = Indeterminate*
        position_employee.is_indeterminate = 'yes'
    If staffing_type <> 1
        position_employee.is_current = 'yes'

I want to be able later on to differentiate, the indeterminate position of an employee but also all the previous position that employee had occupied and be able to pull the employee indeterminate and current position which can be the same but can also be different.

Does this logic makes sense? if yes, how can I do this best?

0

1 Answer 1

0

This explanation does not provide a complete answer to the question, but it does address critical considerations in coming up with a good solution. So it is an answer, just not a complete one.

Since I was the one who discouraged "flags", I'll further qualify my previous answer. The bad flags I mentioned where used to keep track of related database rows that could otherwise be handled by proper, normalized table and relationship design. Such bad flags do not tell you anything about the state of the data objects that you want to store, rather where only for database organizational purposes. Boolean (yes/no) flags may be okay and even necessary for recording an existing, valid state of the object(s) you are storing. That's the first test for determining if the flags are okay.

The next consideration, for any type of flag, is whether or not the chosen database schema allows contradictory states to be stored. The answer to how you handle this situation can be complicated, but

  1. you might be able to change/augment/refactor the database schema to avoid or eliminate contradictory states, or
  2. be prepared to write all queries and updates to consider and handle such possible contradictions. Sometimes this is necessary if the real-world scenario itself allows such contradictions. For instance, perhaps you assign an employee to two positions, thinking that perhaps they can handle 3 positions, so you leave is_indeterminate checked, but then after a week on the job they are overwhelmed and you realize that they could not handle more work, so their is_indeterminate value is unchecked. In that case, there was nothing of an automated fashion that could've fixed that scenario.

On the other hand, what if that employee were now given a 3rd position, but the is_indeterminate checkbox was not properly updated. Now the system has inaccurate data. Is that tolerable? Will the workplace have someone that runs reports to periodically audit and fix bad data? Will your update routines handle possible bad data, so that, for example, the employee isn't underpaid because it says they need more work? Etc. etc.

Per #1 suggestion above, a possible change would be to replace a basic Boolean flag column with a position counter column. A query could simply indicate if the position has the correct number of employees assigned and flag shortages or over-staffing... but this time the "flag" is dynamically determined in the report, not stored in the database where it can become outdated.


Regarding the pseudo-code... We're back to using a bad flag like staffing_stadus_id = 1 == complete. I'll admit that sometimes such a flag can be useful for efficiency or simplicity reasons... like a final stamp that means "it's all done and don't ever bother me with that position again". Maybe that's okay. BUT, on the other hand, simply by adding a record to the [Position_Employee] table should be sufficient to determine if that particular position is complete. In other words, a query looks for all related records and if there are sufficient employees assigned to the position, then it is dynamically determined to be complete... no need to update a separate column with specialized codes that will certainly become outdated either by bugs or people not updating the status appropriately. If the schema/app is designed properly, the only way to mark the position as complete is to actually assign employees properly to the correct table... No accidentally updating the status, but forget to actually add the employee that was put in the position.

But once again, it could be necessary to have a "status flag", for instance if you want to maintain a history of positions, but perhaps a position is not yet filled but also determined to be obsolete. In that case, you would indeed want a flag that you could use to mark it as obsolete.

This might all seem subtle and even contradictory, but go back to the original 2 points and consider why you are adding each flag and consider if it can be implemented in a more natural, relational-database-esque manner.


Also, why are there both employee_id and position_id FK columns in both the [Staffing] table AND the [Position_Employee] tables? Once again, this sets up possible contradictory columns that could be different/outdated between the two tables. Once an employee is chosen for the position, then a record is simply added to the [Position_Employee] table. Why add the employee_id to the [Staffing] table to then just copy it into the [Position_Employee]?

If there is another legitimate business reason for having the employee_id in the [Staffing] table, then schema needs to consider that requirement separately. For instance, perhaps you want to store a potential employee for manual approval, and they are not put into the position until final approval is obtained. Then a better relational-database-esque schema would be another table, perhaps a [Staffing_potential] table with a staffing_id column and employee_id column. Once they are approved, then move (atomic transaction of copy/insert then delete) from the [Staffing_potential] to the [Position_Employee] table. Once again, the staffing status is implied in what tables the rows exist rather than messing with flag columns.


Update

It's always difficult to judge from the questions and the context the reason for each particular detail, despite the attempt to describe those details. It is now apparent that your design and requirements are mature enough that not only are there probably many ways to accomplish what you need, but there is really no answer to "how I can do this best?" without a full iterative analysis. That can't be done on these forums. In fact, I started with Stack Exchange long ago enough that I previously would have rejected this question as "too broad". But the recent push for being "nice and open" has lead me to provide more wordy and specific answers. I won't take back the advise I posted, but I'll wrap up this answer with...

Especially for historical or archival reasons, it may indeed be necessary to store duplicate data or even have supplemental "flag" fields. As long as there is a documented purpose and reason for this, database normalization rules are not necessarily "broken". I ran into that often with financial data where it was critical to record unalterable total transaction amounts along with constituent rows, even though the total could have been obtained from the detail rows. BUT the key is that either documentation or column names or some other feature distinguish between the purposes of the fields, not to be mistaken for non-normalized data. It's up to the developer(s) to ensure that the purpose of such fields are not eventually used for reasons that break stable, normalized design. (FYI, it often good to have separate tables where such historical rows are kept, which are separate from the "working data".)

The fact that you are conscious and aware of the purpose of individual features of your schema is critical. I don't have any further advise about handling the indeterminate employment cases.

3
  • @C Perkins Hello! I don’t know if I can post several comments so 1) Thank you for your very elaborated answer. I cannot say enough how much I like reading your reasoning. It has given me a lot to think about. Perhaps I am not building my tables properly. From your second to last paragraph you asked me why is there employee_id and position_id in Staffing and Employee Table. I wanted to be able to track how an employee was put in a position for archives reason and to be able to pull the staffing later on for modifications and what not.
    – DrD4rk
    Jun 6, 2019 at 10:23
  • 2) However after reading your answer I am thinking, instead of having a trigger and then copying them from two tables, what I need is to directly linking Staffing with Employee_Position with staffing_id FK in Employee_Position. The Staffing table would have the process details that put an employee in a position and it can have as many process as possible. In the Staffing table, I would add a staffing_type which would determine which process the employee was put in that position (indeterminate or determinate).
    – DrD4rk
    Jun 6, 2019 at 10:24
  • 3) Wouldn’t that take care of needing to have to keep track of all these triggers and/or flag and at the same type allow me to pull the employee and all the positions they have occupied?
    – DrD4rk
    Jun 6, 2019 at 10:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.