3

I am having a DB with following tables :

 create table EMPLOYEE
 (
   Emp_ID INT NOT NULL AUTO_INCREMENT,
   Emp_FName VARCHAR(30) NOT NULL,
   Emp_LName VARCHAR(30) NOT NULL,
   Address_ID_Resident INT REFERENCES ADDRESS(Address_ID),
   JobTime_ID CHAR(1) REFERENCES JOBTIME(JobTime_ID),
   PRIMARY KEY(Emp_ID)
 );

Other Table ADDRESS is as follow :

 create table ADDRESS
 (
    Address_ID INT NOT NULL AUTO_INCREMENT,
    Address_St VARCHAR(50) NOT NULL,
    Address_City VARCHAR(30) NOT NULL,
    Address_State VARCHAR(3) NOT NULL,
    Address_PostCode CHAR(4) NOT NULL,
    Add_TypeID CHAR(1) REFERENCES ADDRESSTYPE(Add_TypeID),
    PRIMARY KEY(Address_ID)
 );

ADDRESSTYPE Table is to tell whether address is Residential, Office, Postal

create table ADDRESSTYPE
(
  AddType_ID CHAR(1) NOT NULL,
  Add_Type VARCHAR(15) NOT NULL,
  PRIMARY KEY(AddType_ID)
);

JobTime Table describes whether job of employee is Full Time or Casual.

Create table JOBTIME
(
  JobTime_ID CHAR(1) NOT NULL,
  JobTime_Desc VARCHAR(10) NOT NULL,
  PRIMARY KEY(JobTime_ID)
);

Now as each of them will be having a different salary so For fulltime and casual we have two seperate tables.

 Create table FULLTIME
 (
   Emp_ID INT NOT NULL,
   Emp_salary_yearly DOUBLE(10,2) NOT NULL,
   JobType_ID INT REFERENCES JOBTYPE(JobType_ID),
   FullTimeJob_ID CHAR(1) NOT NULL DEFAULT 'F',
   PRIMARY KEY(Emp_ID)
  );

  ALTER TABLE FULLTIME ADD FOREIGN KEY(Emp_ID) REFERENCES EMPLOYEE(Emp_ID);

  ALTER TABLE FULLTIME ADD FOREIGN KEY(FullTimeJob_ID) REFERENCES JOBFULLTIME(FullTimeJob_ID);

 Create table CASUALTIME
 (
   Emp_ID INT NOT NULL,
   Emp_salary_hourly DOUBLE(10,2) NOT NULL,
   JobType_ID INT REFERENCES JOBTYPE(JobType_ID),
   CasualJob_ID CHAR(1) NOT NULL DEFAULT 'C',
   PRIMARY KEY(EMP_ID)
 );

 ALTER TABLE CASUALTIME ADD FOREIGN KEY(Emp_ID) REFERENCES EMPLOYEE(Emp_ID);

 ALTER TABLE CASUALTIME ADD FOREIGN KEY(CasualJob_ID) REFERENCES JOBCASUALTIME(CasualJob_ID);

Now I want list of names , complete address of all employees sorted by their salary and indicate if the employee works fulltime or casual. Here name is combination of both FName and LName represented in Name column and combination of Street, Suburb State Postcode (e.g. 123 Anzac Pde, Maroubra NSW 2038) in a column labelled ADDRESS . Now I know to do it with help of Join Statements. But if we are supposed to do it without use of JOIN statement then what can be SQL Query for this problem ?

I need to take Address from ADDRESS TABLE and Salary from FULLTIME and CASUAL table depending on job type of employee

Strawberry
  • 33,750
  • 13
  • 40
  • 57
ms8
  • 417
  • 2
  • 13
  • what query you tried so far? – Sachu May 31 '15 at 07:30
  • @Sachu I am facing problem on how to combine Emp_salary_yearly and Emp_salary_hourly into a single column ? – ms8 May 31 '15 at 07:34
  • Don't you think address table should have column which refers to employee id !! I just checked first two table, but I don't know how else can u get employee address!! – Ubaid Ashraf May 31 '15 at 08:01
  • @ubaidgadha the employee table has an FK to the address table. some employees may be living together so this is the correct relationship. – Zohar Peled May 31 '15 at 08:03
  • DOUBLE(10,2). ?? Can I have a job. I don't mind that I won't know exactly how many millions I'm getting paid, so I can probably live without the DECIMAL data type – Strawberry May 31 '15 at 09:20

2 Answers2

4

You have table inheritance - CASUALTIME and FULLTIME inherit off EMPLOYEE. Assuming that an employee MUST be either casual or fulltime, and can't be BOTH casual and fulltime simultaneously, what you can do is use a union to combine the casual and fulltime employees in a derived table (I've called this x), and obtaining a single 'salary' field before joining to the rest of the tables (you will need joins):

 SELECT e.Emp_FName, e.Emp_LName, a.Address_St, a.Address_City, 
        a.Address_State, a.Address_PostCode, x.Salary
 FROM 
 (
    SELECT ct.emp_id, ct.Emp_salary_hourly AS Salary
    FROM CASUALTIME ct

    UNION

    SELECT ft.emp_id, ft.Emp_salary_yearly AS Salary
    FROM FULLTIME ft
 ) x
 INNER JOIN  EMPLOYEE e on x.Emp_ID = e.Emp_ID
 INNER JOIN ADDRESS a on e.Address_ID_Resident = a.Address_ID
 -- Can join to JobType and AddressType same way

It does seem a bit strange to list an annual salary and an hourly rate in a single column as these have different units - it would make more sense to convert the hourly rate to an annual salary or vice versa so they have the same unit.

Also, you shouldn't be using DOUBLE to store financial data - rather use DECIMAL

I've also assumed that JOBTIME is a typo - the table is surely JobType ?

Community
  • 1
  • 1
StuartLC
  • 104,537
  • 17
  • 209
  • 285
  • I dont want to JOIN directly I want to join multiple tables using WHERE clause – ms8 May 31 '15 at 08:16
  • Using [WHERE to join tables is frowned upon](http://stackoverflow.com/a/1018825/314291) - using ANSI joins is the way forward - I can't see why you would want to get into bad habits? In any case, the syntax is `FROM (SELECT...) x, Employee e, ... WHERE e.Emp_ID = x.Emp_ID AND ...` – StuartLC May 31 '15 at 08:23
  • Can you add it to your answer post and also I need to print results sorted by salary – ms8 May 31 '15 at 08:25
  • No, MySql supports ANSI joins and you should use these to join, not `WHERE` clauses – StuartLC May 31 '15 at 08:27
  • How to write x.Salary if All monetary values should be printed with a dollar symbol ($), two digits after the decimal point, and with space for 7 digits before the decimal point ? – ms8 May 31 '15 at 08:52
  • Do that in your presentation tier (e.g. PHP) - you want to keep strong types as far as possible in Sql. – StuartLC May 31 '15 at 08:54
  • Just for sake if we want something like this . Then what must be syntax . Because if I write CONCAT('$',x.salary) it will display "$" But spaces before decimal is still a problem – ms8 May 31 '15 at 08:57
  • 2
    Note that SO isn't a code writing service - you are adding new requirements as you go along. Have a [look here](http://sqlfiddle.com/#!9/da9c7/5) – StuartLC May 31 '15 at 09:11
2

Keeping 2 tables that are almost identical for Full Time and Casual seems to me like the wrong thing to do.
I would merge them to a single table called Salary, and rename the Emp_salary_yearly and Emp_salary_hourly to Emp_salary, since you already have the column for JobType_ID in both tables. Also, the CasualJob_ID and FullTimeJob_ID columns are redundant and useless.

Keep in mind that a salary and job type for any employee may change, so it would be a good idea to keep FromDate and ToDate columns in the salary table as well (using NULL in the ToDate column to indicate that the records is still valid on the current date).

So My suggestion goes like this:

Create table Salary
(
    Emp_ID INT NOT NULL REFERENCES EMPLOYEE(Emp_ID),
    Emp_salary DOUBLE(10,2) NOT NULL,
    JobType_ID INT REFERENCES JOBTYPE(JobType_ID),
    FromDate date NOT NULL,
    ToDate date NULL,
    PRIMARY KEY(Emp_ID, FromDate)
);

Note: this table's primary key is both the employee id and the from date.

This will make for a simple sql statement that looks like this:

SELECT CONCAT(Emp_FName, ' ', Emp_LName) As FullName, 
       CONCAT(Address_St, ' ', Address_City, ' ', Address_PostCode) As Address,
       Emp_salary_yearly,

       JobType_Desc,
       FromDate,
       ToDate
FROM EMPLOYEE e 
INNER JOIN ADDRESS a ON e.Address_ID_Resident = a.Address_ID
INNER JOIN Salary s ON(e.Emp_Id = Salary.Emp_Id)
INNER JOIN JOBTYPE j ON(s.JobType_ID = j.JobType_ID)

Update Answering your comments: First, don't use implicit joins. ANSI-SQL supports explicit joins for more then 20 years now, and there really is nothing better in implicit joins.
Explicit joins are more readable and easier to handle then implicit joins.

Second, in the case where the 2 salary tables can't be combined into one, you can either use a LEFT JOIN on both, or use an INNER JOIN on a derived table that is the result of a UNION between them as suggested by StuartLC in his answer.

This is how it would look like using left joins:

SELECT CONCAT(Emp_FName, ' ', Emp_LName) As FullName, 
       CONCAT(Address_St, ' ', Address_City, ' ', Address_PostCode) As Address,
       CASE WHEN Emp_salary_hourly IS NOT NULL THEN  
               CONCAT('$', LPAD(Emp_salary_hourly, 7, ' ') 
            WHEN Emp_salary_yearly IS NOT NULL THEN  
               CONCAT('$', LPAD(Emp_salary_yearly , 7, ' ')
       END As Emp_Salary, 
       JobType_Desc,
       FromDate,
       ToDate
FROM EMPLOYEE e 
INNER JOIN ADDRESS a ON e.Address_ID_Resident = a.Address_ID
INNER JOIN JOBTIME j ON(e.JobTime_ID = j.JobTime_ID )
LEFT JOIN FULLTIME f ON(e.Emp_Id = f.Emp_Id)
LEFT JOIN CASUALTIME c ON(e.Emp_Id = c.Emp_Id)

Note #1: This assumes that the employee can only have one job time.
Note #2: If neither the FULLTIME nor the CASUALTIME have a record for the emp_id then Emp_Salary will be null.

Community
  • 1
  • 1
Zohar Peled
  • 79,642
  • 10
  • 69
  • 121
  • I dont want to JOIN directly I want to join multiple tables using WHERE clause. Also I can't merge the two tables like this.Reason being I had provided a part of tables only here. I am using these both tables in different way as a whole in my project – ms8 May 31 '15 at 08:18
  • Also You may have not noticed that they both depend on two different tables names JOBFULLTIME and JOBCASUALTIME – ms8 May 31 '15 at 08:23
  • how to write Emp_salary if All monetary values should be printed with a dollar symbol ($), two digits after the decimal point, and with space for 7 digits before the decimal point – ms8 May 31 '15 at 08:53
  • see [this answer](http://stackoverflow.com/questions/10556404/mysql-select-int-as-currency-or-convert-int-to-currency-format) on how to format data in MySql – Zohar Peled May 31 '15 at 08:56
  • It dont look for 7 spaces – ms8 May 31 '15 at 09:00
  • What it do is something that was not required.Like if its 2000000.67 then it shows $2000000. – ms8 May 31 '15 at 09:11
  • did you check out the link StuartLC provided in his last comment? Cast as decimal (10,2) on your columns: `CONCAT('$', LPAD(FORMAT(CAST(Emp_salary_hourly as decimal (10,2)(, 2), 7, ' ') ` – Zohar Peled May 31 '15 at 09:16