I am wondering if it is okay to have master and detail table for employees?
As per requirments, data can filtered by department by country and by employee code on report level.
If employee's department or country code is changed then the changes will go in detail table and old record will be set to IS_ACTIVE = 'T'.
---------------------Master Table--------------------------------------
**EMPLOYEE_CODE** VARCHAR2(20 BYTE) NOT NULL,
EMAIL VARCHAR2(100 BYTE)
FIRST_NAME VARCHAR2(50 BYTE)
LAST_NAME VARCHAR2(50 BYTE)
WORKING_HOURS NUMBER
---------------------Detail Table--------------------------------------
**PK_USER_DETAIL_ID** NUMBER,
FK_EMPLOYEE_CODE VARCHAR2(20 BYTE),
FK_GROUP NUMBER,
FK_DEPARTMENT_CODE NUMBER,
FK_EMPLOYER_COUNTRY_CODE VARCHAR2(5 BYTE),
FK_MANAGER_ID VARCHAR2(20 BYTE),
FK_ROLE_CODE VARCHAR2(6 BYTE),
START_DATE DATE,
END_DATE DATE,
IS_ACTIVE VARCHAR2(1 BYTE),
INACTIVE_DATE DATE
Employee table will be linked with Timesheet table and for timesheet reports data can be filtered by department, country and by employee code.
OPTION : I
Have one employee table with one Primary Key and create a new entry whenever department or role is updated for an employee.
Add country and department code in the timesheet table.
--> This way i don't need to search employee table.
OPTION : II
Have master and detail table.
Add country and department code in timesheet table.
--> This way i don't need to search employee table plus i will have master detail table
OPTION : NEW
Have master and detail table.
Timesheet table will have EmpCode.
If user move to new location or change department then Insert a new row in the detail table with the new dept Code and same Emp No.
Update an old row and set the End Date field so if he changes his location or department then the End Date field needs to be updated.
Which one is a best option and is there any other better option available?
This is one way of implementing this requirement, and it's an approach many people take. However, it has on emajor drawback: every time you query the current employee status you need to filter the details on start and end date. This may seem like a trivial thing, but you wouldn't believe how much confusion it can cause, and it has performance implications too.
These things matter, because most of the time you will want only the current details, with queries on history being a relatively rare occurence. Consequently you are hampering the implementation of your most common use case to make it easier to implement a less-used one. (Of course I am making assumptions about your business requirements, and perhaps yours is not a run-of-the-mill employee application...)
The better solution would be to have two tables, an EMPLOYEES table with all the detail columns too and an EMPLOYEES_HISTORY table with the same columns plus the start and end date. When you change an employee's record insert a copy of the old record in the History table, probably by a trigger. Your standard processes have just the one table to query, and your history needs are met fully.
By the way, your proposed data model is wrong. Working_hours, email_address and last_name are definitely things which can change and perhaps even first name (e.g. through changes in personal circumstances such as getting married). So all those columns should be held in your details name
Option 3 - Please note that this option is useful only for the reports Point of View.
Whenever you insert the data, create a De-Normalized entry in a new table.
Whenever an entry will be updated, the De-Normalized entry will be updated in the new table.
The New Table will have all De-Normalized columns of Employee.
So while Performing the search, this will benefit you as the results will be calculated without using Joins. Thus, the access time will be reduced.
Records in the new table will be Created/Updated in The Insert/Update Trigger.
Improvements in Option - 2 and Option 1
Don't create redundancy by adding duplicate columns.
Related
I have an employees table and the ERD looks like this
I want to add more requirements. I want to add if the employees are seasonal or fulltime. I thought of adding an extra column on the duration table where I can track if employees are seasonal or fulltime. If seasonal, then some of the seasonal employees might be interns from colleges. For them, I want to add another table to track the university they are enrolled in. is this approach okay or should I create different table for status of employees?
If there are only two options available, i.e. whether an employee is
full time or
seasonal
then the simplest option is to add a "checkbox" column, e.g.
alter table employees add cb_seasonal number(1) default 0 not null;
which will be set to 0 (i.e. everyone is NOT seasonal which means that everyone IS full time employed). When someone switches to a seasonal status, you'd just "check" it by updating the row and setting the column value to 1.
However, if there were more statuses, then it would be better to use additional table. You'd still have to alter the employees table and add a foreign key constraint to that "additional" table you created.
There are three tables linked to each other as in the diagram.
This Youtuber is using IsDeleted=0 or IsDeleted=1 column to indicate that the data in the table is deleted or not.
When one SQL table is linked to another table, is it impossible to delete the data from the database? If it is impossible, then I think its really bad. Isn't there any workarounds for completely deleting the data?
Also, maybe Facebook also does something like IsDeleted=1 and they don't let us see us our own data when we 'delete' it while they can still access our past interests. What do you think?
No, data can always be deleted from a database. There may be constraints what has to happen before the data gets deleted (permissions, foreign-key constraints, etc), but it eventually can be deleted.
A column such as that is frequently used for maintaining data history in the application. The "links" you refer to are called Foreign Key relationships and they are used to maintain integrity within relational data. The IsDeleted column in the resultset doesn't have anything to do with the FK.
Also, that column would not indicate that the table is deleted, but rather the row of data the values of the column belong to.
Well defined and static and structured arrangement of data is one of the most important things in relational databases. In the tables you show, Employee belongs to a department. Now if you delete the department, you have a broken record in the Employee table. This is why, SQL will not allow you to delete the department.
To solve this, you will need to either stop the deletion of department with message like "There are users in this department. Cannot be deleted." or remove the department id (set it to null) from the employee records which belong to this department.
There are situations, business needs where the data is to be retained for various reasons. In those cases, IsActive like flags come to rescue. The records can be filtered using them and thus are hidden on the screen. This is generally referred to as soft delete.
Actually, i think it is very good practice to do Soft Delete rather than hard delete because you can safely recover the data later. To your question you can only delete parent table data if there are no more child table data. Else you get this errror:
the delete statement conflicted with the reference constraint ...
for example in your database say you have data of employee and departments. e.g this is your department table:
ID DepartmentName
1 HR
2 marketing
and this is your employee table:
ID DepartmentId Name Address
1 1 Name1 address1
2 1 Name2 address2
3 1 Name3 address3
Now if you want to delete marketing department from Department table , you can delete it easily and there is no error. But now if you try to delete HR department you will get error as mentioned above because the HR department Id(i.e. 1) is already linked with another table called Employee table. So if you want to delete HR department anyhow, you must first delete all the record from employee table with DepartmentId=1 . otherwise you can use the approach as the youtuber you mentioned.
Hope it helps !
I need to create a database to manage a gas station.
I'm thinking of a basic product inventory and sales data model, but it need some changes.
See http://www.databaseanswers.org/data_models/inventory_and_sales/index.htm. This is how they proceed: the manager keep tracks of the inventory and sales twice a day, each time a gas pump attendant is in charge, and takes the responsibility of the sales.
How can I keep track of this ?
Using the Model that you provided you could use the first Model as reference:
And I would use all the six (6) tables namely:
1) Products
2) Product_Types
3) Product_In_Sales
4) Sales
5) Daily_Inventory_Level
6) Ref_Calendar
But I had to make some changes by alteration and adding:
First I need to include SalesPerson table that would have at least the following fields
1) SalesPersonID
2) Lastname
3) Firstname
4) Alias
In line with that I therefore need to add SalesPersonID as Foreign key in
my Sales table.
Now since you want to have twice a day Inventory then you could approach in many ways
you could add single primary key for Daily_Inventory_Level table or you could add a new field named Inventory_Daily_Flag which has either only the value of 1 or 2. If 1 that means that's the first inventory and if 2 that means that's the second inventory for the day. And that means by the way that you're Primary and Foreign Key at the same time would no longer be just Day_Date and ProductID but also Inventory_Daily_Flag for Daily_Inventory_Level table.
And also in line with that, that means you need to also to add a field in your Product_In_Sales like FlagForInventory with Boolean as Data Type.
So, let's say a Supervisor came in to do the first inventory, then the products sold
in Product_In_Sales for the day would be flag as True for the FlagForInventory and
then would be transferred to Daily_Inventory_Levels with Inventory_Daily_Flag field
as 1 to indicate as the first inventory and of course the Level also would be updated.
And so when the days end and the 2nd inventory is to be executed then those
sales for the day from Product_In_Sales table whose FlagForInventory is false then
it would be flag as True for FlagForInventory and then transferred again to Daily_Inventory_Levels with Inventory_Daily_Flag as 2 indicating the second inventory.
And of course you need to update the Level as well.
Does it make sense? If not I could always change the approach? ;-)
I have 2 questions regarding a project. Would appreciate if I get clarifications on that.
I have decomposed Address into individual entities by breaking down to the smallest
unit. Bur addresses are repeated in a few tables. Like Address fields are there in the
Client table as well as Employee table. Should we separate the Address into a separate table with just a linking field
For Example
Create an ADDRESS Table with the following attributes :
Entity_ID ( It could be a employee ID(Home Address) or a client ID(Office Address) )
Unit
Building
Street
Locality
City
State
Country
Zipcode
Remove all the address fields from the Employee table and the Client table
We can obtain the address by getting the employee ID and referring the ADDRESS table for the address
Which approach is better ? Having the address fields in all tables or separate as shown above. Any thoughts on which design in better ?
Ya definitely separating address is better Because people can have multiple addresses so it will be increasing data redundancy.
You can design the database for this problem in two ways according to me.
A. Using one table
Table name --- ADDRESS
Column Names
Serial No. (unique id or primary key)
Client / Employee ID
Address.
B. Using Two tables
Table name --- CLIENT_ADDRESS
Column Names
Serial No. (unique id or primary key)
Client ID (foreign key to client table)
Address.
Table name --- EMPLOYEE_ADDRESS
Column Names
Serial No. (unique id or primary key)
Client ID (foreign key to employee table)
Address.
Definitely you can use as many number of columns instead of address like what you mentioned Unit,Building, Street e.t.c
Also there is one suggestion from my experience
Please add this five Columns in your each and every table.
CREATED_BY (Who has created this row means an user of the application)
CREATED_ON (At what time and date table row was created)
MODIFIED_ON (Who has modified this row means an user of the application)
MODIFIED_BY (At what time and date table row was modified)
DELETE_FLAG (0 -- deleted and 1 -- Active)
The reason for this from point of view of most of the developers is, Your client can any time demand records of any time period. So If you are deleting in reality then it will be a serious situation for you. So every time when a application user deleted an record from gui you have to set the flag as 0 instead of practically deleting it. The default value is 1 which means the row is still active.
At time of retrieval you can select with where condition like this
select * from EMPOLOYEE_TABLE where DELETE_FLAG = 1;
Note : This is an suggestion from my experience. I am not at all enforcing you to adopt this. So please add it according to your requirement.
ALSO tables which don't have any significant purpose doesn't need this.
Separating address into a seperate table is a better design decision as it means any db-side validation logic etc. only needs to be maintained in one place.
I have a table Salary with a column PersonalId and a table Person with a column Name.
In the first table salary data will saved with a PersonalId which relates it to the Person table. In salary bill all data will gather together and Person name will be referenced from Person table.
After 1 year a specific person name will change from Michael to Maic. Now I want the last year salaries bill remain with previous person name Michael and the new salaries bill generate by new name Maic.
How we can do that?
It could depend on what type of operation you need to to most and on how much people change their name, because the number of joins you may need to make could vary a lot.
keep a field in Person that points to the next Person which is a change of name
keep another key in Person that varies only for the physical person
keep a limited number of names in Person that someone could dispose of, with an index of the current name
in another table you keep the relations between the various name of the Person
It could depend on what rules of normalization you follow, for now I'm not thinking about that.
Anyway, with the first case you don't need to change Salary, but to reconstruct the identity of a Person you need multiple requests or at least a stored procedure.
In the second case you still don't need to change Salary because you add a field to Person, but to get all the Salary entries for that physical person you'll need some work, again probably a stored procedure to get the added field and then something that joins all the Salary entries.
The third maybe is the simplest, but also the limited one, and you need in Salary another field that tells the index of the name to use in that entry.
The last case gives you a stable identity, but it may need some work because of the added table, and still there are multiple implementations. You could have salary reference that table instead of Person, or you could consult that table only when you need all the data, but you cannot reference its primary key from Salary because it would not permit to discriminate the name.
Lunadir's right in a certain way -- but all of those approaches are complex, and of rather great difficulty.
The other way -- simpler, and perhaps more correct & robust -- is to keep NAME and PAID_DATE columns in Salary or SalaryPaid, and write the actual name & date paid at the time the payment is made.
Good old batch-processing style -- and it has the benefit of actually capturing the key financial facts, of what payment was made & what name it was made to, which are the actual auditable transaction history.
Do you pay each Salary entry individually, or in bunch (PaySlip or SalaryPaid)? Put the NAME column wherever you record the actual payment & timestamp it occurred.