gaufler
gaufler

Reputation: 165

Is the query correct

I have 6 tables (SQL Fiddle):

CREATE TABLE Department(
    Dname varchar(10),
    Dnumber int(5),
    Mgrno int(5),
    PRIMARY KEY(Dnumber)
    );

CREATE TABLE Employee(
    Fname varchar(20),
    Lname varchar(20),
    Empno int(5),
    Bdate date,
    Address varchar(10),
    Salary float(5),
    Dnumber int(5),
    PRIMARY KEY(Empno),
    FOREIGN KEY(Dnumber) REFERENCES Department(Dnumber)
    );


CREATE TABLE Location(
    Dnumber int(5),
    Dlocation varchar(10),
    PRIMARY KEY(Dlocation),
    FOREIGN KEY(Dnumber) REFERENCES Department(Dnumber)
    );

CREATE TABLE Project(
    Pname varchar(10),
    Pnumber int(5),
    Location varchar(10),
    Dnumber int(5),
    PRIMARY KEY(Pnumber),
    FOREIGN KEY(Dnumber) REFERENCES Department(Dnumber)
    );

CREATE TABLE Timesheet(
    Empno int(5),
    Pnumber int(5),
    Hours_per_day int(5),
    FOREIGN KEY(Empno) REFERENCES Employee(Empno),
    FOREIGN KEY(Pnumber) REFERENCES Project(Pnumber)
    );

 CREATE TABLE Dependent(
    Empno int(5),
    Dependent_name varchar(10),
    DOB date,
    Sex varchar(5),
    Relationship varchar(10),
    FOREIGN KEY(Empno) REFERENCES Employee(Empno)
    );

I am asked to write a query to retrieve the details of all the employees who works on the project number 30,40,50

Here is my attempt:

      SELECT * FROM Employee JOIN Timesheet
      ON  Employee.Empno = Timesheet.Empno 
      WHERE (Pnumber = 30 OR Pnumber = 40 OR Pnumber = 50)

Is my implementation of the condition after the WHERE clause appropriate ?

The question is from a written exam so, I didn't provide any data set.

Thanks in advance!

Upvotes: 0

Views: 125

Answers (2)

spencer7593
spencer7593

Reputation: 108400

Yes, the conditions in the WHERE clause appear to be valid.

There's a whole lot of table definitions, but we don't see any definition of the Works_on table. I expect this was actually meant to be a reference to Timesheet table.

Note that the join operation will cause multiple rows to be returned for an employee; this query will return the Employee row for each matching row in Timesheet.

I recommend qualifying all column references, even if they aren't ambiguous in the statement. That aids the future reader, and also prevents the query from breaking when columns of the same name are added to another table.

Also, I'd recommend ditching the * in the SELECT list, and explicitly list the columns to be returned. Or, if we have to use a * to return all columns, qualify that with a table name (or table alias).


As written, the query would return a list of employees that had worked on any one of the projects. That is an Employee that worked on projects 30 and 40, but has not worked on project 50, would be included.

Another interpretation of the requirement would be to return only those employees that have worked on all three of the projects. That result would require a different query.

Here's one (rather long winded) possible approach) to satisfying that specification:

SELECT e.*
  FROM Employee e
 WHERE EXISTS ( SELECT 1 
                  FROM Timesheet t1
                 WHERE t1.empno = e.empno
                   AND t1.pnumber = 30
              ) 
   AND EXISTS ( SELECT 1
                  FROM Timesheet t2
                 WHERE t2.empno = e.empno
                   AND t2.pnumber = 40
              ) 
   AND EXISTS ( SELECT 1
                  FROM Timesheet t3
                 WHERE t3.empno = e.empno
                   AND t3.pnumber = 50
              ) 

There are other query patterns that would also satisfy the specification.

For example, using an aggregate expression in the HAVING clause...

SELECT e.*
  FROM ( SELECT t.empno 
           FROM Timesheet t
          WHERE t.pnumber in (30,40,50)
          GROUP
             BY t.empno
         HAVING COUNT(DISTINCT t.pnumber) = 3
       ) q
  JOIN Employee e
    ON e.empno = q.empno 
 ORDER
    BY e.empno

Or, as @MKhalidJunaid suggests, we could use conditional aggregation ...

SELECT e.*
  FROM ( SELECT t.empno
           FROM Timesheet t
          GROUP
             BY t.empno
         HAVING MAX(IF( t.pnumber = 30 ,1,0))
            AND MAX(IF( t.pnumber = 40 ,1,0))
            AND MAX(IF( t.pnumber = 50 ,1,0))
       ) q
  JOIN Employee e
    ON e.empno = q.empno
 ORDER
    BY e.empno

Upvotes: 4

Red Boy
Red Boy

Reputation: 5729

You could simply use IN.

     SELECT * FROM Employee JOIN timesheet
  ON  Employee.Empno = timesheet.Empno 
  WHERE Pnumber in( 30,40,50)

Since it's exam, they sometimes do trick of words and any of project or must be all the project. My answer is for Anyone of project.

If it's later, you need to use AND.

Upvotes: 1

Related Questions