Unable to make desired JOINS between multiple tables - sql

I've got 3 tables
Plan:
plan_id emp_id duration
123 1010 30
456 1011 40
789 1012 60
PlanEmp:
plan_id emp_id
123 2131
456 3131
789 4131
Emp:
emp_id Name
1010 Andy
1011 Cole
1012 John
2131 Sam
3131 Kim
4131 Ray
Desired Summary Output:
plan_id Name duration
123 Andy 30
123 Sam 30
456 Cole 40
456 Kim 40
789 John 60
789 Ray 60
Query that I'm trying to modify to get the above result:
SELECT P.plan_id
,E.Name
,P.duration
FROM Plan P
LEFT JOIN Emp E
ON P.emp_id = E.emp_id
LEFT JOIN PlanEmp PE
ON P.plan_id = PE.plan_id
I'm unable to figure how to pull the Employee details using the PlanEmp table AND the Plan table to get the summary output.

This should work:
SELECT sub.plan_id, sub.emp_id, Emp.name, Plan.duration
FROM
(SELECT plan_id, emp_id
FROM Plan
UNION
SELECT plan_id, emp_id
FROM PlanEmp) sub
LEFT JOIN Emp
ON sub.emp_id = Emp.emp_id
LEFT JOIN Plan
ON sub.plan_id = Plan.plan_id
ORDER BY plan_id
Tested here: http://sqlfiddle.com/#!9/21ca79/4

Use the below script.
;With cte_1
As( select plan_id,emp_id
From plan
UNION
Select plan_id,emp_id
From plan_emp)
Select c.plan_id,e.Name,p.Duration
From cte_1 c
Join plan p on c.plan_id=p.plan_id
Join emp e on c. Emp_id=e.emp_id

I'm sure there's a logical explanation for this and since my reputation is not at the level to comment yet, but why is emp_id on both the Plan and PlanEmp tables? If you can normalize this, that would be a good idea to move emp_id off of the Plan table to the PlanEmp table.

Your table design is not following the needed Normalization practices. You should merge the table Plan and EmpPlan.
or
Your design should be (To normalize more):
Table: Plan
Plan_ID
Duration
Table: PlanEmp
Plan_ID
Emp_ID
Your existing structure can be queried with multiple ways but they may not efficient. Another way:
Select ISNULL(P.plan_id, PE.plan_id) Plan_ID, E.Name,
(Select Duration from #Plan pp Where pp.plan_id = ISNULL(P.plan_id, PE.plan_id)) as Duration
from Emp E
left Join #lan P on E.emp_id = P.emp_id
left Join PlanEmp PE on E.emp_id = PE.emp_id
Where P.emp_id IS NOT NULL or PE.emp_id is not null

Related

Need help fetching data from DB2

S.no
emp_id
emp_name
Dept
1
100
John
Sales
2
100
John
Accounts
3
200
Mike
Sales
4
300
Mark
Sales
5
300
Mark
Accounts
6
400
Tom
Sales
I need to pull all the emp_id who are linked ONLY to Sales Dept and ignore the ones that are in both Sales and Accounts. I am using DB2 z/os. Any suggestions would be helpful? Thanks in advance.
An anti-join will produce the result you want.
For example:
select s.*
from employee s
left join employee a on a.emp_id = s.emp_id and a.dept = 'Accounts'
where s.dept = 'Sales' and a.emp_id is null
For good performance you can try adding the index:
create index ix1 on employee (emp_id, dept);

SQL Query: Customer Table Contains Different type of EmpIDs and i want to get their name in a single row

I got a customer table and each customer has 4 different employeeID (tranieeID,RepresenterID,CoridatorID and ManagerID) I want to get all these employees name rather then their ID in single row.
CustomerTable
|CustomerID|CustomerName|tranieeID|RepresenterID |CoridatorID |ManagerID
------------------------------------------------------------------------
01 Mr T 100 101 102 103
EmployeeTable
EmpID | EmpName
---------------
100 Mr A
101 Mr B
102 Mr C
103 Mr D
What I need
CustomerID | CustomerName | tranieeName | RepresenterName | CoridatorName | ManagerName
----------------------------------------------------------------------------------------
01 Mr T Mr A Mr B Mr C Mr D
I did inner join but I got 4 Rows, is there any way to get all these with a single row?
Thank you for your help!
JOIN should work. I would recommend LEFT JOIN in case any of the values are not filled in:
select c.*,
et.empname as traineeName,
er.empname as RepresenterName,
ec.empname as CoridatorIDName,
em.empname as ManagerName
from customertable c left join
employeetable et
on c.traineeID = et.empid left join
employeetable er
on c.RepresenterID = et.empid left join
employeetable ec
on c.CoridatorID = ec.empid left join
employeetable em
on c.ManagerID = em.empid
You could use a correlated subquery in each instance, such as
select c.CustomerId, CustomerName,
(select Empname from EmployeeTable e where e.EmpID=c.TranieeId) TraineeName,
(select Empname from EmployeeTable e where e.EmpID=c.RepresenterId) RepresenterName,
... etc
from CustomerTable c

Retrieving dissimilar data using WHERE NOT in the joins?

I need to retrieve the name of those departments in which no students are enrolled.
Table: department
dept_id dept_name
1 IT
2 Electrical
3 Civil
4 Mechanical
5 Chemical
Table: stud_member
f_name dept_id age
AB 2 19
Rose 3 22
May 1 20
Noor 1 21
Haya 1 19
April 3 23
Sakina 2 20
For example the names of mechanical and chemical. I have written this query for it using outer join (explicitly maybe?) But is shows an error.
please tell me that why i cannot write:
SELECT dept_id, dept_name
FROM department
LEFT JOIN stud_member ON (WHERE NOT department.dept_id = stud_member.dept_id);
I will be grateful if anyone will tell me the correct answer!
Assuming dept_id in stud_member can not be NULL which is true when dept_id is a FOREIGN KEY
SELECT dept_id, dept_name
FROM department
WHERE dept_id NOT IN (SELECT dept_id FROM stud_member);
as suggested using NOT EXISTS does not have this problem
SELECT d.dept_id, d.dept_name
FROM department d
WHERE NOT EXISTS (SELECT * FROM stud_member s WHERE d.dept_id = s.dept_id);
You can select all departments where Right part of Left JOIN is NULL
SELECT d.dept_id, d.dept_name
FROM department d
LEFT JOIN stud_member sm ON d.dept_id = sm.dept_id
WHERE sm.dept_id IS NULL

Create view by joining three tables in SQL

I have three tables STUDENTS, SUBJECTS, RANK ,with data as -
1) STUDENTS [NAME(Primary)]
NAME
--------
Alex
Greg
2) SUBJECTS [ID(Primary)]:
ID
--------
100
101
102
3) RANK [SEQ(Primary), NAME, ID, RANK]
SEQ NAME ID RANK
------ ------- ------ ------
1 Alex 100 A
2 Greg 100 A
3 Greg 101 B
I want to create a view that should display data as
NAME ID RANK
------- ------ ------
Alex 100 A
Alex 101 Z
Alex 102 Z
Greg 100 A
Greg 101 B
Greg 102 Z
So, for every student and for every subject, the View should display the RANK if present in RANK table, else replace the NULL with 'Z'.
I'm a newbie to SQL. So any help in forming the query would be deeply appreciated!
cross join student and subject then left outer join the result with rank to get ranks for all (student, subject) combination. selecting column with NVL OR COALESCE will replace NULL with 'z'.
SELECT st.name,
su.id,
NVL(ra.rank,'Z') Rank, --COALESCE(ra.rank,'Z') Rank
FROM student st
CROSS JOIN subject su
LEFT OUTER JOIN rank ra
ON ra.name = st.name
AND ra.id = su.id
ORDER BY st.name,su.id
Note : ORDER BY can be removed from above query if you don't need.
fiddle
SELECT r.NAME, r.ID, NVL(r.RANK, 'Z')
FROM RANK r, studendts st, SUBJECTS su
WHERE st. NAME = r. NAME
AND su.ID = r.ID
ORDER BY 1,2,3

sql query for getting data from two related tables

I have two tables, employee and inventory. One employee can have zero or more inventories.
I would like to list employee information along with at most one inventory information
and count of inventories belongs to one employee.
employee table
emp_num last_name first_name
-----------------------------------
100 john smith
101 mike pet
102 jes lyoid
inventory table
inv_num emp_num
---------------------------
12 100
13 100
15 100
30 102
desired Output
emp_num last_name invnum count(inv_num)
--------------------------------------------------------------------------
100 john 12 3
101 mike - 0
102 jes 30 1
What sql query can I use in this case?
Try this:
SELECT emp_num, last_name, MAX(inv_num) AS invnum, COUNT(inv_num) AS inv_count
FROM employee e LEFT OUTER JOIN inventory i ON e.emp_num = i.emp_num
GROUP BY e.emp_num, e.last_name
You could do something like this
Select E.Emp_Num,
e.Last_name,
MIN(Inv_Num) AS OldestInv,
COUNT(Inv_Num) AS TotalInv
FROM Employee E
LEFT OUTER JOIN Inventory I
(E.Emp_Num = I.Emp_Num)
GROUP BY E.Emp_Num, E.Last_Name
This will give you the minimum invoice number and the total count. The left outer join is the key
SELECT
e.emp_num,
e.last_name,
IFNULL(MAX(i.inv_num),'-') AS 'invnum',
COUNT(i.inv_num) AS 'count(inv_num)'
FROM
employee e LEFT JOIN inventory i
ON e.emp_num = i.emp_num
GROUP BY
e.emp_num, e.last_name