Getting Empty Set in MySQL on using "not in" - mysql

I'm a beginner at MySQL. Due to this, there may be some errors. I have an employee department database for learning purposes. I have stored the supervisorENO for employees who have got a supervisor. If an employee does not have supervisor, their supervisorENO is null.
I have to retrieve the employees' name who is not supervisor. I ran the following command and got Empty set. I was not able to figure it out.
Here is my table:
MariaDB [EMP_DEPT]> select * from EMPLOYEE;
+-----+---------------+---------------------------+---------------+------------+------+------------+----------+
| Eno | Ename | Job_type | SupervisorENO | Hire_date | Dno | Commission | Salary |
+-----+---------------+---------------------------+---------------+------------+------+------------+----------+
| 111 | Aman Singh | HR Manager | NULL | 2000-01-23 | 50 | NULL | 5000.00 |
| 112 | Ankesh Kumar | HR Assistant | 111 | 2005-10-30 | 50 | NULL | 4000.00 |
| 113 | Gaurav Singh | Account Manager | NULL | 2002-07-09 | 60 | 100.00 | 6000.00 |
| 114 | Sanjeet Kumar | Accounting Clerk | 113 | 2015-04-18 | 60 | NULL | 4500.00 |
| 115 | Rajnish Yadav | Production Manager | NULL | 1980-12-04 | 10 | 150.00 | 5500.00 |
| 116 | Sumit Sharan | Production Incharge | 115 | 1995-02-24 | 10 | NULL | 4500.00 |
| 117 | Amartya Sinha | R&D Scientist | NULL | 2010-03-15 | 20 | NULL | 10000.00 |
| 118 | Shahnwaz Khan | R&D Associate Engineer | 117 | 2016-05-23 | 20 | NULL | 4000.00 |
| 119 | Sonu Giri | Purchase Executive | NULL | 2013-06-17 | 30 | 140.00 | 7000.00 |
| 120 | Kaushik Kumar | Purchase Specialist | 119 | 2018-08-13 | 30 | 4500.00 | 4000.00 |
| 121 | Vishal Yadav | Chief Marketing Officer | NULL | 1995-11-19 | 40 | 250.00 | 10000.00 |
| 122 | Satyam Jha | Digital Marketing Manager | 121 | 2004-09-29 | 40 | NULL | 4500.00 |
+-----+---------------+---------------------------+---------------+------------+------+------------+----------+
12 rows in set (0.001 sec)
MariaDB [EMP_DEPT]> select Ename from EMPLOYEE where Eno not in (select distinct SupervisorENO from EMPLOYEE);
Empty set (0.001 sec)
I am expecting the names of employees with Eno 112, 114, 116, 118, 120, 122 as they are not supervisor. Please help me in figure it out.

select distinct SupervisorENO from EMPLOYEE will also return NULL, any any value when compared to NULL will not actually return True or False, it will return unknown, so to speak. You can read more about that here for example.
So in order to fix your query, you need to exclude NULLs:
select Ename
from employee
where Eno not in (select distinct SupervisorENO
from employee
where supervisoreno is not null);
Here's a working demo on dbfiddle

You can simply query
select Ename from employee
where SupervisorEno is not null;
which will return those who have a supervisor, ie. are not themselves a supervisor.
select Ename from employee
where SupervisorEno is null;
Will return the supervisors.
It is better to avoid sub-queries when not strictly needed.

Related

How to update a column to match data from another column in the same table

I'm trying to get a query going that would update the parent_id row to reflect the corresponding username that possesses the same member_id as the parent_id.
Below is a representation of the db_name.members table, and I want to convert the parent_ids into their corresponding usernames.
+--------+----------+-----------+-----------+
| name | username | member_id | parent_id |
+--------+----------+-----------+-----------+
| Jeff | Jeff | 167 | NULL |
| Asia | Asia | 143 | NULL |
| Bogart | Bogart | 389 | 167 |
| Greg | Greg | 894 | NULL |
| Hatsy | Hatsy | 328 | 167 |
| Super | Super | 721 | NULL |
| Goku | Goku | 534 | 894 |
| Banana | Banana | 520 | NULL |
| Kyle | Kyle | 456 | 520 |
+--------+----------+-----------+-----------+
What it should look like after:
+--------+----------+-----------+-----------+
| name | username | member_id | parent_id |
+--------+----------+-----------+-----------+
| Jeff | Jeff | 167 | NULL |
| Asia | Asia | 143 | NULL |
| Bogart | Bogart | 389 | Jeff |
| Greg | Greg | 894 | NULL |
| Hatsy | Hatsy | 328 | Jeff |
| Super | Super | 721 | NULL |
| Goku | Goku | 534 | Greg |
| Banana | Banana | 520 | NULL |
| Kyle | Kyle | 456 | Banana |
+--------+----------+-----------+-----------+
This is my current (not working) query:
UPDATE members SET parent_id=(SELECT name FROM members WHERE member_id=parent_id);
You can use this, using a UPDATE with INNER JOIN:
UPDATE members m1 INNER JOIN members m2 ON m1.parent_id = m2.member_id
SET m1.parent_id = m2.username
Keep in mind that in case the parent_id column is a integer / numeric column you can't set the username to this column. You can use a SELECT instead of a UPDATE:
SELECT m1.name, m1.username, m1.member_id, m2.username AS parent_username
FROM members m1 LEFT JOIN members m2 ON m1.parent_id = m2.member_id
demo on dbfiddle.uk

Joins with two tables conditionally based on the value of ONE column

I have following tables to manage purchase and issues of items.
item Table
+---------+-----------+
| item_id | item_name |
+---------+-----------+
| 500 | A4 |
| 501 | A5 |
| 502 | B5 |
| 503 | B4 |
| 504 | A3 |
+---------+-----------+
supplier Table
+-------------+---------------+
| sup_id | supplier_name |
+-------------+---------------+
| 1 | ABC Suppliers |
| 2 | DEF Suppliers |
| 3 | GHI Suppliers |
+-------------+---------------+
officer Table
+------------+--------------+
| officer_id | officer_name |
+------------+--------------+
| 1 | Jhon |
| 2 | William |
| 3 | Ken |
| 4 | Robert |
+------------+--------------+
purchase / issue table
+-----------+---------+---------+---------+------------+-----+-------------+
| update_id | bill_no | sup_id | item_id | date | qty | type |
+-----------+---------+---------+---------+------------+-----+-------------+
| 1000 | 10 | 1 | 500 | 2018-11-01 | 50 | purchase |
| 1001 | 40 | 1 | 500 | 2018-11-02 | 25 | purchase |
| 1002 | 32 | 2 | 500 | 2018-11-04 | 10 | issue |
| 1003 | 25 | 3 | 500 | 2018-11-05 | 12 | issue |
| 1004 | 14 | 1 | 500 | 2018-11-08 | 22 | purchase |
| 1005 | 55 | 2 | 501 | 2018-11-09 | 10 | purchase |
| 1006 | 30 | 2 | 502 | 2018-11-10 | 40 | purchase |
+-----------+---------+---------+---------+------------+-----+-------------+
02) purchase / issue table holds the purchase details and issue details by mentioning the "type" at the end of table.
03) I need to get the following output.
+-----------+------------------------------+------------+-----+------------+
| item_name | supplier_name / officer_name | date | qty |type |
+-----------+------------------------------+------------+-----+------------+
| A4 | ABC Suppliers | 2018-11-01 | 50 | purchase |
| A4 | ABC Suppliers | 2018-11-02 | 25 | purchase |
| A4 | William | 2018-11-04 | 10 | issue |
| A4 | Ken | 2018-11-05 | 12 | issue |
| A4 | ABC Suppliers | 2018-11-08 | 22 | purchase |
| A5 | DEF Suppliers | 2018-11-09 | 10 | purchase |
| B5 | DEF Suppliers | 2018-11-10 | 40 | purchase |
+-----------+------------------------------+------------+-----+------------+
03) I used the following query
select item.item_name,
supplier.supplier_name,
purchase.date,
purchase.qty,
purchase.type
from purchase
join item on item.item_id = purchase.item_id
where supplier.sup_id in (select sup_id from supplier)
04) But I did't get the desired output. I can not understand what I am going wrong. Can anyone help me ?
In your SELECT clause, you are referring to supplier table, without joining to that table. Now, it seems that you want to show officer_name when the purchase type is issue, else supplier_name when it is purchase.
We can do a LEFT JOIN to both the tables, and use CASE .. WHEN to determine the respective name.
I have removed the WHERE .. IN subquery, which does not seem to serve any purpose here.
select item.item_name,
CASE purchase.type
WHEN 'purchase' THEN supplier.supplier_name
WHEN 'issue' THEN officer.officer_name
END AS `supplier_name_officer_name`
purchase.date,
purchase.qty,
purchase.type
from purchase
join item on item.item_id = purchase.item_id
left join supplier on purchase.sup_id = supplier.sup_id
left join officer on purchase.sup_id = officer.officer_id
You need to join the supplier just as you did for the item.
And I see no point in the where clause at all.

Sql query related to my given tables

emp table
+-----+-------+-----+---------+
| eno | ename | dno | salary |
+-----+-------+-----+---------+
| 101 | sam | 1 | 1200.00 |
| 102 | ram | 1 | 1300.00 |
| 103 | alia | 1 | 2500.00 |
| 104 | tina | 2 | 1300.00 |
| 105 | avni | 2 | 1800.00 |
| 106 | suraj | 2 | 2000.00 |
| 107 | chris | 3 | 1500.00 |
| 108 | ben | 3 | 2000.00 |
| 109 | rina | 3 | 3300.00 |
+-----+-------+-----+---------+
Dept table
+-----+-------+-----------+
| dno | dname | location |
+-----+-------+-----------+
| 1 | csc | new delhi |
| 2 | phy | mumbai |
| 3 | chem | hyderabad |
+-----+-------+-----------+
I want to write a query
to display department no. ,department name, average salary of all department
Here dno Is foriegn key in emp table
Dno is a primary key in dept table
I tried many times but sometime there is an error and sometimes wrong output
My desire output is
+-----+-------+-------------+
| dno | dname | avg(salary) |
+-----+-------+-------------+
| 1 | csc | 1666.6666 |
| 2 | phy | 1700.0000 |
| 3 | chem | 2266.6666 |
+-----+-------+-------------+
This is classic 'group by' usage.
Try this:
select d.dno , d.dname, avg(salary)
from employee e LEFT JOIN department d on e.dno=d.dno
GROUP BY e.dno
Here is your query:
SELECT e.dno DNO, d.dname DNAME, AVG(e.salary) SALARY
FROM emp e, dept d
WHERE e.dno = d.dno
GROUP BY DNO

Self-refering table. MySQL

I have another question. I don't seem to fully grasp the concept.
I have a table:
EMPLOYEES
| EMP_NO | APELLIDO | OFFICE | DIRECTOR | START_DATE | SALARY | COMMISSION | DEP_NO |
I have to obtain data of employees who's OFFICE is 'DIRECTOR' (easy, but... ) and I also have to include a column that would return full salary (salary+commission) of all the employees who are theirs subordinates.
Now I know that I need to 'copy' the table so I am able to make it to refer to itself (EMPLOYEES e1, EMPLOYEES e2 etc.). But I am getting really worked up in that obtaining total of salary of those subordinates.
Any thoughts?
(pls help)
EDIT
Sorry guys, true. My fault. OK, so here are some sample data:
+--------+----------+------------+----------+------------+---------+----------+--------+
| EMP_NO | SURNAME | OFFICE | DIRECTOR | START_DATE | SALARY |COMMISSION| DEP_NO |
+--------+----------+------------+----------+------------+---------+----------+--------+
| 7499 | ALONSO |SALESPERSON | 7698 | 1981-02-23 | 1400.00 | 400.00 | 30 |
| 7521 | LOPEZ | EMPLOYEE | 7782 | 1981-05-08 | 1350.50 | NULL | 10 |
| 7654 | MARTIN |SALESPERSON | 7698 | 1981-09-28 | 1500.00 | 1600.00 | 30 |
| 7698 | GARRIDO | DIRECTOR | 7839 | 1981-05-01 | 3850.12 | NULL | 30 |
| 7782 | MARTINEZ | DIRECTOR | 7839 | 1981-06-09 | 2450.00 | NULL | 10 |
| 7839 | REY | CEO | NULL | 1981-11-17 | 6000.00 | NULL | 10 |
| 7844 | CALVO |SALESPERSON | 7698 | 1981-09-08 | 1800.00 | 0.00 | 30 |
| 7876 | GIL | ANALIST | 7782 | 1982-05-06 | 3350.00 | NULL | 20 |
| 7900 | JIMENEZ | EMPLOYEE | 7782 | 1983-03-24 | 1400.00 | NULL | 20 |
+--------+----------+------------+----------+------------+---------+----------+--------+
What I need to achieve now is to return table with details of employees GARRIDO and MARTINEZ (EMP_NO 7698 and 7782) along with additional column that would contain total salary of all theirs direct subordinates. Something like that:
+--------+----------+------------+----------+------------+---------+----------+--------+-----------+
| EMP_NO | SURNAME | OFICIO | DIRECTOR | FECHA_ALTA | SALARIO | COMISION | DEP_NO | TOTAL_EMP |
+--------+----------+------------+----------+------------+---------+----------+--------+-----------+
| 7698 | GARRIDO | DIRECTOR | 7839 | 1981-05-01 | 3850.12 | NULL | 30 | 6700 |
| 7782 | MARTINEZ | DIRECTOR | 7839 | 1981-06-09 | 2450.00 | NULL | 10 | 1350.50 |
+--------+----------+------------+----------+------------+---------+----------+--------+-----------+
I believe this should do it. You just need to JOIN to the other rows that you need, then it's a simple matter of grouping to get the aggregate amount that you want.
SELECT
D.emp_no,
D.apellido, -- Why is there one column named in Spanish and the rest in English?
D.office,
D.director,
D.start_date,
D.salary,
D.commission,
D.dep_no,
SUM(COALESCE(S.salary, 0) + COALESCE(S.commission, 0)) AS subordinates_compensation
FROM
Employees D
LEFT OUTER JOIN Employees S ON S.director = D.emp_no
WHERE
D.office = 'Director'
GROUP BY
D.emp_no,
D.apellido,
D.office,
D.director,
D.start_date,
D.salary,
D.commission,
D.dep_no

How to select the employee who worked the longest hours on project

I have the following assignment table:
+-----------+----------------+-------------+
| ProjectID | EmployeeNumber | HoursWorked |
+-----------+----------------+-------------+
| 1000 | 1 | 30.00 |
| 1000 | 8 | 75.00 |
| 1000 | 10 | 55.00 |
| 1100 | 4 | 40.00 |
| 1100 | 6 | 45.00 |
| 1200 | 1 | 25.00 |
| 1200 | 2 | 20.00 |
| 1200 | 4 | 45.00 |
| 1200 | 5 | 40.00 |
| 1300 | 1 | 35.00 |
| 1300 | 8 | 80.00 |
| 1300 | 10 | 50.00 |
| 1400 | 4 | 15.00 |
| 1400 | 5 | 10.00 |
| 1400 | 6 | 27.50 |
+-----------+----------------+-------------+
In the following table I found the two projects that are over budget, but I must find the employee number of the person that worked the most hours on each project:
CREATE VIEW OVER AS
SELECT P.Department, P.ProjectID, A.EmployeeNumber, A.HoursWorked
FROM project AS P JOIN assignment AS A
ON P.ProjectID = A.ProjectID
GROUP BY P.ProjectID
HAVING MAX(P.maxhours) < SUM(A.hoursworked);
+------------+-----------+----------------+-------------+
| Department | ProjectID | EmployeeNumber | HoursWorked |
+------------+-----------+----------------+-------------+
| Marketing | 1000 | 1 | 30.00 |
| Marketing | 1300 | 1 | 35.00 |
+------------+-----------+----------------+-------------+
The correct employeenumber should be 8 for both projects and 75 and 80 hours.
Any idea how to retrieve the MAX hours worked for these individual projects?
The easy way is like this:
select * from (
select ProjectID, EmployeeNumber
from assignment
group by 1, 2
order by sum(HoursWorked) desc
) x
group by 1
See live demo on SQLFiddle.
This works due to mysql's special handling of group by, which allows not all non-aggregate columns to be listed and in such cases returns just the first row encountered for each group.