Self Join with Correlated Subquery - sql

I need to find an employee with a salary greater than their Manager. For this, I used to following query and it works;
SELECT
e1.EmpID
,e1.EmpName
,e1.EmpSalary
,e1.ManagerID
FROM empsalary e
INNER JOIN empsalary e1 ON e.EmpID = e1.ManagerID
WHERE e1.EmpSalary > e.EmpSalary
But following one is not working. I want to know why it is not? Why it's result is null? What should be correct format?
SELECT *
FROM empsalary as e
WHERE e.empsalary=(
SELECT e1.empsalary
FROM empsalary as e1
WHERE e.EmpID = e1.ManagerID
AND e1.EmpSalary > e.EmpSalary)
Sample data and code here;
EmpID EmpName EmpSalary ManagerID
----------- ---------- -------------------- -----------
1 Neevan 100000 6
2 Mukesh 30000 6
3 Disha 50000 6
4 Martin 90000 6
5 Roy 170000 6
6 Anvesh 168000 NULL
CREATE TABLE empsalary
(
EmpID INT
,EmpName VARCHAR(10)
,EmpSalary BIGINT
,ManagerID INT
)
INSERT INTO empsalary
VALUES
(1,'Neevan',100000,6)
,(2,'Mukesh',30000,6)
,(3,'Disha',50000,6)
,(4,'Martin',90000,6)
,(5,'Roy',170000,6)
,(6,'Anvesh',168000,NULL)

Your correlations are all backwards. The right way is:
SELECT e.*
FROM empsalary e
WHERE e.empsalary > (SELECT m.empsalary
FROM empsalary m
WHERE m.EmpID = e.ManagerID
);
Notice that I have used the m table alias for the manager record. This helps to follow the logic.

There's no need for me to re-write how to do it, as Gordon has done a good enough job already, but I can explain why yours returned null...
For me to answer this, I needed to re-write yours slightly to help me to read it. It is essentially the same as yours. Also, similarly to how Gordon has done, I've substituted e for m and e1 for e. I've also called your tables tblSalaries, so that the table names aren't the same as the column name:
SELECT *
FROM tblSalaries as m
WHERE m.empsalary=(
SELECT e.empsalary
FROM tblSalaries as e
WHERE e.ManagerID = m.EmpID
AND e.EmpSalary > m e.EmpSalary)
If we work backwards and interpret the last part firstly:
...
(
SELECT e.empsalary
FROM tblSalaries as e
WHERE e.ManagerID = m.EmpID
AND e.EmpSalary > m.EmpSalary)
Firstly, WHERE m.ManagerID = e.EmpID is saying 'Find all employees in e who's manager ID is the same as the employee ID in m'. Considering there is only one managerID (6), then records 1-5 from e will all match the manager record, on m (6) on this.
Your next clause AND e.EmpSalary > m.EmpSalary is finding those who's salary is greater than the managers'. Therefore, you are left with record 5 (Roy) as you intended.
Now to return to your main query:
SELECT *
FROM tblSalaries as m
WHERE m.empsalary= (...tblSalaries as e...)
We have established that table e in the brackets has returned Roy, but we have also established that it only matches records in table m, where m is a manager. Ultimately, you are asking then to find where the manager's salary = Roy's salary; the answer, null.

Related

My SQL Join is only producting half the right aggregate output

SELECT E.DNO as DeptNum, COUNT(E.SSN) as EmployeeCount, COUNT(D.ESSN) as DependentCount
FROM Dependent D
RIGHT OUTER JOIN Employee E ON D.ESSN = E.SSN
GROUP BY E.DNO
The goal is to find the total number of employees and total number of dependents for every department. I am utilizing an Employee Table that features Employee, SSN, Department Number and a Dependent Table that has Dependent SSN, Birthdate, and Gender.
The output should be as follows
Dept Num Employee Count DependentCount
1 1 0
2 3 7
3 5 2
But, instead I am getting
Dept Num Employee Count DependentCount
1 1 0
2 9 7
3 4 2
One thing of note is the dependent's SSN is equivalent to the parent's SSN - that is the only way to define the relationship between the tables. Also, I know I need an outer join because we want to list ALL departments, despite the fact there are 0 mentions of it for Dept 1 in Dependent Table.
Can anyone tell me why this isn't working?
Try using distinct so things don't get double counted:
SELECT E.DNO as DeptNum, COUNT(DISTINCT E.SSN) as EmployeeCount,
COUNT(DISTINCT D.ESSN) as DependentCount
FROM Employee E LEFT JOIN
Dependent D
ON D.ESSN = E.SSN
GROUP BY E.DNO

subquery and join not giving the same result

1
select *
from employees
where salary > (select max(salary) from employees where department_id=50)
2
select *
from employees e left join
employees d
on e.DEPARTMENT_ID =d.DEPARTMENT_ID
where d.salary > (select max(salary) from employees where department_id=50)
why the second query is giving multiple record
i want achieve the same result as of 1st query using join.....
Thanks in Advance......
Rocky, the first select is correct. Why do you want to do any join? Without further information the objective of the second select is not clear (nonsense).
I can't see the point about joining against the same table by DEPARTMENT_ID. Anyway, the problem about duplicates is because you are joining the same two tables by a key is not pk, basically you are multiplyng each employee for all the employees of the same department. This version eliminate duplicates but still has no improvement from the first one.
select *
from employees e left join
employees d
on e.employee_ID = d.employee_ID
where d.salary > (select max(salary) from employees where department_id=50)
You are probably looking for an anti join. This is a pattern mainly used in a young DBMS where IN and EXISTS clauses are slow compared to joins, because the developers focused on joins only.
You are looking for all employees whose salaries are greater than all salaries in department 50. With other words: WHERE NOT EXISTS a salary greater or equal in department 50.
Your query can hence be written as:
select *
from employees e
where not exists
(
select null
from employees e50
where e50.department_id = 50
and e50.salary >= e.salary
);
As an anti join (an outer join where you dismiss all matches):
select *
from employees e
left join employees e50 on e50.department_id = 50 and e50.salary >= e.salary
where e50.salary is null;

self join condition

I have a confusion in self join condition
eg:i have a table named as 'employee' and column as employeeid,name,managerid
just a basic syntax
select e.employeeid,m.managerid
from employee e
left join employee m
**on e.managerid=m.employeeid
or e.employeeid=m.managerid**
please tell me differnce between the text with in **
I think your query is wrong to start with - right now you're getting the employee ID of the employee and the manager ID of the manager. So you're skipping a "generation"
I think you want:
select e.employeeid, m.employeeid
from employee e
left join employee m
on e.managerid=m.employeeid
That will give you the employee IDs in the first column and their manager's ID in the second column.
The second one would be the opposite:
select e.employeeid, m.employeeid
from employee e
left join employee m
on e.employeeid=m.managerid
Would give you the manager ID in the first column and their employee's IDs in the second column. In that case it would make more sense to swap the m and e aliases assuming they stand for manager and employee but that won't change the result.
the first part of your where
e.managerid=m.employeeid
will get your subordinate employees
and the second part
e.employeeid=m.managerid
will get your manager.
selecting m.managerid in your query doesn't really make sense.. if you look at this sample data and query it might make more sense to you.
CREATE TABLE employee (
employeeid INT,
managerid INT
)
INSERT INTO employee
VALUES (1,NULL),
(2,1),
(3,1),
(4,2),
(5,4);
SELECT e.employeeid employee,
m.employeeid relatedemployee,
CASE WHEN e.managerid = m.employeeid THEN 'manager'
ELSE 'employee'
END AS relationship
FROM employee e
LEFT JOIN employee m ON e.managerid = m.employeeid
OR e.employeeid = m.managerid
output:
employee relatedemployee relationship
----------- --------------- ------------
1 2 employee
1 3 employee
2 1 manager
2 4 employee
3 1 manager
4 2 manager
4 5 employee
5 4 manager

Can't insert date from table to other with 2 condition

i want insert date from table to other
with 2 condition from same row
(view picture in yellow part)
thanks
The problem is that the IN in the where clause can only have one colymn, not two. You could re-write it as:
from emp e
inner join emp2 e2 on e.Id = e2.Id and e.storeId = e2.storeId
I think that this would get you the effect.
You can declare only one field in "not in subselect" approach.
You should give this workaround a try:
select .... from emp e
where not exists (
select 1 from emp2 e2 where e.id = e2.id and e.storeid = e2.storeid
)
I guess it provides exactly the same result as you need

SQL Assertion: The manager complex

I have the following schema:
Emp(eid int, ename varchar(50), salary float, email varchar(80))
Works(eid int, did int, pct_time float)
Dept(did int, budget float, managerid int)
eid is for employee id.
did is for department id.
I've bolded primary keys.
managerid is a foreign key, as well as eid and did in Works.
Now, I'd like to add a "manager complex" assertion that ensure a manager will always have a higher salary than any employee that he/she manages.
Here's what I've been thinking:
CREATE ASSERTION managerComplex
CHECK
( NOT EXISTS (SELECT M.salary
FROM Dept D, Emp M
WHERE D.managerid = M.eid) <=
(SELECT E.salary
FROM Works W, Emp E
WHERE W.eid = E.eid) AND
D.did = W.did);
Is this even close to right?
Also, maybe I should have just made a couple CHECKs instead of an insertion?
I feel like multiple CHECKs is sloppier but would probably be easier to get right.
EDIT: The main reason I am asking is because I don't know if I'm correctly understanding NOT EXISTS
I think you are close. My edit to your trial:
CREATE ASSERTION managerComplex
CHECK
( NOT EXISTS ( SELECT *
FROM Dept D, Emp M
WHERE D.managerid = M.eid
AND M.salary < ANY
( SELECT E.salary
FROM Works W, Emp E
WHERE W.eid = E.eid
AND D.did = W.did
AND M.eid <> E.eid
)
)
)
For NOT EXISTS ( SELECT ...) to be true, the SELECT ... must return no results.
You want to create a SELECT statement that will return any employee with a salary higher than the manager listed for the department(s) they work for. See if you can write that query, and then place it inside the NOT EXISTS
I'm not entirely sure what you wrote is even valid SQL, but it's certainly not what you want. I have a potential answer for you, but as this was marked homework, I'd like to attempt to prod you in the right direction before providing a complete answer.
As OP said the homework has been turned in...
CREATE ASSERTION managerComplex
CHECK
(NOT EXISTS (SELECT E.salary
FROM Emp M, Dept D, Works W, Emp E
WHERE M.eid = D.managerid AND
W.did = D.did AND
E.eid = W.eid AND
E.salary > M.salary))
My NOT EXISTS has a query inside of it, that will return results if there are any employee salaries higher than their respective manager's salary. I look at all employees who work for a department, and only pull them into the result set if their salary is higher than the manager for that department's salary.
I'm not even sure your SQL is valid, as you have a (SELECT ...) <= (SELECT ...) AND .... Comparing result sets with a <= doesn't make any sense to me. It's possible that's just SQL I've never used, but... I've never used it.