Please start any new threads on our new
site at https://forums.sqlteam.com. We've got lots of great SQL Server
experts to answer whatever question you can come up with.
Author |
Topic |
jhermiz
3564 Posts |
Posted - 2007-04-26 : 16:03:49
|
The company I work for has this awful database for logging vacation.We've talked about recreating it and I am having a bit of a difficult time dealing with another developer. Basically the application allows our employees to log vacation time.There are some rules however:BenefitNon Exempt Status• Less than 5 years – 2 weeks or 80 hours-per-year (3.08 hours-biweekly),• 5 – 10 years – 3 weeks or 120 hours-per-year (4.62 hours-biweekly),• More than 10 years – 4 weeks or 160 hours-per-year (6.16 hours-biweekly).Exempt Status• Less than 5 years – 3 weeks or 120 hours-per-year (4.62 hours-biweekly),• 5-10 years – 4 weeks or 160 hours-per-year (6.16 hours-biweekly),• More than 10 years – 5 weeks or 200 hours-per year (7.70 hours-biweekly).Basically an employee is either exempt or non-exempt and based on those rules you get a certain amount of accural. One of the developers here wants to store running totals and amount of total annual benefit hours right inside the employees table. I keep explaining that this sort of thing is wrong and referred him to some normalization tips.My thinking was a master employee table with just employee information and a field as to whether the employee is Exempt or Non-Exempt.Then the rules that I pasted above would be in their own seperate table linking the employee with the status as well as doing a EmployeesTable.HireDate BETWEEN TodaysDate - EmployeesTable.HireDate to find out which rule the employee would follow (<5 years, 5-10 years, >10 years). Hopefully that BETWEEN wont bite my thinking :|, as I've never had to deal with such an app.In any event in addition to this I thought that the actual transactions (accruing vacation, taking vacation, selling vacation off) all of these transactions would go into one table. This way you may have + / - values and the SUM of these values would give you your available vacation hours. Basically each line item will have an identifier as to what "Type" the line item is (vacation day, accrual, accural benefit, sell vacation, etc).My counterpart thinks otherwise and to have a table of just accurual vacation hours, a table of used vacation hours, etc.The thing that may be a bit more difficult for me is the part where an employee gets accrued bi-weekly hours. For instance, if the employee is non-exempt and he / she has been here <5 years then they accrue 3.08 hours bi-weekly. Plus the maximum number of vacation hours that can be accrued is double the eligible annual benefit. So in this case:Non Exempt Employees• Less than 5 years – 4 weeks or 160 hours maximum accrual,• 5 – 10 years – 6 weeks or 240 hours maximum accrual,• More than 10 years – 8 weeks or 320 hours maximum accrual.Exempt Employees• Less than 5 years – 6 weeks or 240 hours maximum accrual,• 5-10 years – 8 weeks or 320 hours maximum accrual,• More than 10 years – 10 weeks or 400 hours maximum accrual.Im wondering if I should just setup 2 jobs one to handle the biweekly stuff and the other to check maximum accruals?How does this sound, or what may / may not bite me?Anyone develop something similiar that can give me some pointers...surely Jeff's around :).Thanks,JonProgrammers HowTo's -- [url]http://jhermiz.googlepages.com[/url] |
|
SwePeso
Patron Saint of Lost Yaks
30421 Posts |
Posted - 2007-04-26 : 16:46:21
|
Sample data/expexted output and an explanation of what "exempt" is?Peter LarssonHelsingborg, Sweden |
 |
|
jhermiz
3564 Posts |
Posted - 2007-04-26 : 18:23:59
|
quote: Originally posted by Peso Sample data/expexted output and an explanation of what "exempt" is?Peter LarssonHelsingborg, Sweden
I should of known better...The defintion of exempt is a salaried employee in the US. non-exempt is hourly based employee.Sample data will be hard to give you as I am looking to develop a new system, the current system in place is really bonkers and there is not much I can pull from that (As the data is not normalized and to this day I do not understand the flow of the application nor can I understand all the redundancy).I was looking more towards someone telling me I'm on the right path as opposed to the other developer. I can provide what from the description above of some sample tables, fields, and potentioal data.First I was thinking an StatusType table with the following:StatusType-----------StatusTypeID (varchar) PKDescription (varchar / nullable)... Sample data would for now just be the two types:Non-ExemptExemptThen based on the two types there are the rules I talked about which I listed:Non Exempt Status• Less than 5 years – 2 weeks or 80 hours-per-year (3.08 hours-biweekly),• 5 – 10 years – 3 weeks or 120 hours-per-year (4.62 hours-biweekly),• More than 10 years – 4 weeks or 160 hours-per-year (6.16 hours-biweekly).Exempt Status• Less than 5 years – 3 weeks or 120 hours-per-year (4.62 hours-biweekly),• 5-10 years – 4 weeks or 160 hours-per-year (6.16 hours-biweekly),• More than 10 years – 5 weeks or 200 hours-per year (7.70 hours-biweekly).So we'd be looking at a table called StatusTypeRules:StatusTypeRules----------------StatusTypeID varchar (together with yearslow and yearshigh make pk)YearsLow tinyintYearsHigh tinyintWeeks tinyintHoursAnnualBenefit int (stores # of hours annually given based on todaysDate - employee hiredate)HoursBiWeeklyBenefit int (stores accural of bi-weekly based on the rules)MaxAccural int (stores max employee can accrue)MaxPayInLieuOfTime int (stores max hours employee can use for selling their vacation, pay instead of time off)Sample data for this could include:StatusTypeID: Non-ExemptYearsLow: 0YearsHigh: 4Weeks: 2HoursAnnualBenefit: 80HoursBiWeeklyBenefit: 3.08MaxAccural: 160MaxPayInLieuOfTime: 20So basically this follows the above rule. In this case an employee that is non-exempt with less than 5 years of work with the company (0 low to and including 4 as high) gets an annual benefit of 80 hours. Their biweekly accrual (every other week) they get 3.08 hours additional. Their maximum accural they can receive is 160 hours (this means if they still have 160 and they continue to accrue it will NOT be counted, lost days for the employee). Finally the number of hours they can sell (pay in lieu of time off is 20 for non-exempt, It is 40 for exempt.I'd have a row for each rule by the way, non-exempt 5-10 years, non-exempt 10+ years and same thing for the exempt (3 rules) as I listed them out.Then I would have the employees table:Employees----------LoginID pkFName varcharLName varchar......HireDate datetime(important as TodaysDate - HireDate determines which rule the employee takes on)StatusTypeID (references the statustypeid from previous table)....No need to get into details with this table, its just a listing of our employees. The key is that the StatusTypeID and Year(Todays Date) - Year(hire date) = determines the rule the employee takes on.I would include a vacationTypes table:VacationTypes--------------VacationTypeID varchar pkDescriptionValues could include:Vacation DayPay in lieur of time off (Sell your vacation)Accural Bi-WeeklyAccrual AnnuallyThen of course my vacations table:Vacations-----------VacationID pkVacationTypeID (references above table for the kind of vacation)EmployeeID (references the employee)VacationDate (date taken for vacation)Hours (number of hours vacation).....My idea is TO NOT create seperate tables for Accruing Vacation, Used Vacation, and Wanting to use vacation, which the other developer thinks is right. My idea is to store all the vacations in one table, and identify them by the VacationTypeID. I would then take a running SUM() of all the vacation types by employeeID to determine how much vacation the employee has. My co-worker believes in storing this running sum in an actual field :|..I dont like that idea.I would then have a holidays table:Holidays---------HolidayID PK datetime ???Description varcharClientID (this field is used to reference the Employee.ClientID field because we have employees across the US and in some states vacations differ in our company).So basically my question was merely am I going about this the right way, or is my co-worker right? I guess I was looking for ideas and how to handle what I talked about. For instance, I stated in the first thread about vacation BI WEEKLY accuruals and Yearly Accurals..should I handle those via a job that is run and checks the users employee hire date and gives them their annual accural for instance ?ThanksProgrammers HowTo's -- [url]http://jhermiz.googlepages.com[/url] |
 |
|
Michael Valentine Jones
Yak DBA Kernel (pronounced Colonel)
7020 Posts |
Posted - 2007-04-27 : 00:16:36
|
What you are doing is basically an inventory system for keeping track of vacation hours inventory, so it has many of the same problems.You mentioned the idea of a calculating a running total vs. just storing the amount. The problem with having only a running total is that it makes it difficult to purge old data, because you need all of it to be able to calculate the current amount. Also, calculating the total will take longer over time as the number of rows in the table increases. Just having a row in a table with the current balance is not very good either, because it is easy for it to get out of sync.It is common to solve this problem by having a row that represents a balance at a point in time, like beginning of month, and then calculate the current balance by adding up the rows for the current period only. Then you can remove older transactions rows that are no longer needed. You can also have the start of period balances in a separate table; it is especially useful in inventory applications to be able to quickly look at balances at a point in time. A disadvantage of this method is that the start of period rows can use a lot more space in situations where you have fairly low transaction volume compared to the number of periods.I have also seen the approach of calculating the balance after every transaction, and including that balance on each transaction row. One problem is that transactions do not always arrive in time sequence, so you may get an adjustment for something that happened weeks ago, and then you have to recalculate the balance on each individual transaction going forward from that point in time. Also, it makes it more difficult to do a balance at a point in time, unless you also insert dummy transactions at the start of periods to hold the balance at that point in time.As for having one table vs. many tables, you might need to combine both approaches. Put the attributes that are common to all types of transactions in the main table: user id, transaction date, transaction type, etc. Enter attributes that are specific to a particular type of transaction in tables that are related to the main transaction table. This is especially good if you have individual transactions that have related data with complex relationships. For example, if someone sells a vacation day, someone else is buying a day, so you will need a sale row that to related to the two different transactions for different employees. This is similar to an inventory transaction that transfers products from a warehouse to a store.Another thing you may want to consider is how this system will relate to the company’s financial systems. If it is producing transactions that will feed the financial systems, you will also have to allow for those requirements. For example, if it is necessary to adjust the vacation used for someone for last year, you may need to report this in a current financial period, because last years books are closed. You may need to record a separate financial reporting date for each transaction that could be different than the actual date of the transaction, and have clearly understood rules for this. You might also have to calculate the balance at a point in time differently for financial reporting purposes.I hope this is helpful. I know I am not giving you any clear answers here; I’m only trying to bring up issues that I had to deal with. It’s easier to deal with these problems at the design phase than after implementing a system.CODO ERGO SUM |
 |
|
jsmith8858
Dr. Cross Join
7423 Posts |
Posted - 2007-04-27 : 09:13:15
|
Jon -- I agree with your approach and what MVJ says as well. Keep it as a large transactional table with the different transaction types and simply aggregate as necessary. Running totals can be displayed on a report or webpage as necessary very easily, much easier than doing in T-SQL; the most important thing that your code will be concerned with will be grand totals, not running totals, and we all know that is very easy to aggregate off of a transactional table.I also agree that storing rates and types and min/max years and all that as much as possible in tables is the way to go. Looks like you are going in the right direction.It's tough to explain to a co-worker why a design that might seem more complicated at first is actually much more flexible and even simpler than the "one big table that we update" approach that they are used to, hopefully you will have success in educating them.I did a similar application that was a full-blown timesheet, with certain project codes that correlated to vacation, unpaid time off, sick time, etc. What you have described is basically how I did it (though this was back in 1999 and I used a combination of Excel and Access since that's all I had to work with at the time! you should have seen this beauty .. though the schema was pretty well designed,I thought, and it did work quite well for about 4-5 years).You can also keep benefit accrual transactions in 1 table and the actual time taken in another table if you like and always UNION ALL the two transactional tables together as well. - Jeffhttp://weblogs.sqlteam.com/JeffS |
 |
|
jhermiz
3564 Posts |
Posted - 2007-04-27 : 09:19:43
|
quote: Originally posted by Michael Valentine Jones What you are doing is basically an inventory system for keeping track of vacation hours inventory, so it has many of the same problems.You mentioned the idea of a calculating a running total vs. just storing the amount. The problem with having only a running total is that it makes it difficult to purge old data, because you need all of it to be able to calculate the current amount. Also, calculating the total will take longer over time as the number of rows in the table increases. Just having a row in a table with the current balance is not very good either, because it is easy for it to get out of sync.It is common to solve this problem by having a row that represents a balance at a point in time, like beginning of month, and then calculate the current balance by adding up the rows for the current period only. Then you can remove older transactions rows that are no longer needed. You can also have the start of period balances in a separate table; it is especially useful in inventory applications to be able to quickly look at balances at a point in time. A disadvantage of this method is that the start of period rows can use a lot more space in situations where you have fairly low transaction volume compared to the number of periods.I have also seen the approach of calculating the balance after every transaction, and including that balance on each transaction row. One problem is that transactions do not always arrive in time sequence, so you may get an adjustment for something that happened weeks ago, and then you have to recalculate the balance on each individual transaction going forward from that point in time. Also, it makes it more difficult to do a balance at a point in time, unless you also insert dummy transactions at the start of periods to hold the balance at that point in time.As for having one table vs. many tables, you might need to combine both approaches. Put the attributes that are common to all types of transactions in the main table: user id, transaction date, transaction type, etc. Enter attributes that are specific to a particular type of transaction in tables that are related to the main transaction table. This is especially good if you have individual transactions that have related data with complex relationships. For example, if someone sells a vacation day, someone else is buying a day, so you will need a sale row that to related to the two different transactions for different employees. This is similar to an inventory transaction that transfers products from a warehouse to a store.Another thing you may want to consider is how this system will relate to the company’s financial systems. If it is producing transactions that will feed the financial systems, you will also have to allow for those requirements. For example, if it is necessary to adjust the vacation used for someone for last year, you may need to report this in a current financial period, because last years books are closed. You may need to record a separate financial reporting date for each transaction that could be different than the actual date of the transaction, and have clearly understood rules for this. You might also have to calculate the balance at a point in time differently for financial reporting purposes.I hope this is helpful. I know I am not giving you any clear answers here; I’m only trying to bring up issues that I had to deal with. It’s easier to deal with these problems at the design phase than after implementing a system.CODO ERGO SUM
Mike are you kidding me, your information is really helpful..it is best to know what can bite me in the rear end early.I do appreciate your insight as I do like to get your input on matters as complicated as these.Thanks again! Programmers HowTo's -- [url]http://jhermiz.googlepages.com[/url] |
 |
|
jhermiz
3564 Posts |
Posted - 2007-04-27 : 09:21:57
|
quote: Originally posted by jsmith8858 Jon -- I agree with your approach and what MVJ says as well. Keep it as a large transactional table with the different transaction types and simply aggregate as necessary. Running totals can be displayed on a report or webpage as necessary very easily, much easier than doing in T-SQL; the most important thing that your code will be concerned with will be grand totals, not running totals, and we all know that is very easy to aggregate off of a transactional table.I also agree that storing rates and types and min/max years and all that as much as possible in tables is the way to go. Looks like you are going in the right direction.It's tough to explain to a co-worker why a design that might seem more complicated at first is actually much more flexible and even simpler than the "one big table that we update" approach that they are used to, hopefully you will have success in educating them.I did a similar application that was a full-blown timesheet, with certain project codes that correlated to vacation, unpaid time off, sick time, etc. What you have described is basically how I did it (though this was back in 1999 and I used a combination of Excel and Access since that's all I had to work with at the time! you should have seen this beauty .. though the schema was pretty well designed,I thought, and it did work quite well for about 4-5 years).You can also keep benefit accrual transactions in 1 table and the actual time taken in another table if you like and always UNION ALL the two transactional tables together as well. - Jeffhttp://weblogs.sqlteam.com/JeffS
Definately thanks for your input, I knew in the back of my mind that somehow 'Jeff has had to do something like this in the past'. Definately thanks for the input I am glad the "experts" have some agreement here. I'm going to try to avoid the UNIONs for now...I'm creating some diagrams today to explain to him and a few others how the system will basically look and relate. I definately appreciate your feedback and knowledge Jeff.Thanks,JonProgrammers HowTo's -- [url]http://jhermiz.googlepages.com[/url] |
 |
|
|
|
|
|
|