How does the WITH clause know which table to work with? - sql

I came across the following SQL statement in a book:
WITH dcount AS
(
SELECT deptno, COUNT(*) AS dcount
FROM employees
GROUP BY deptno
)
SELECT
e.lname EMP_lastname,
e.deptno e_dept,
d1.dcount edept_count,
m.lname manager_name,
m.deptno mdept,
d2.dcount mdept_count
FROM
employees e,
dcount d1,
employees m,
dcount d2
WHERE
e.deptno = d1.deptno
AND e.mgr = m.empno
AND m.deptno = d2.deptno
AND e.mgr = 7839
The purpose of the statement is to display an employees name, the department they work in, the number of coworkers in the department, the manager's name, and the number of people in the manager's department.
The part that confuses me is where it says d1.count and d2.count. How is it counting different things if the count is based on the same WITH statement?

The main query is joining the same CTE but is using different joining predicates each time:
It's joining d1 using e.deptno = d1.deptno.
It's joining d2 using m.deptno = d2.deptno.
Therefore each resulting row is picking a different row from the CTE.

Related

practice sql explanation

http://studybyyourself.com/seminar/sql/exercises/8-3/?lang=en
Please provide data about all employees whose salary is higher or equal to the average salary of employees working in the same department (regardless if employees have left the company or not). Required attributes are last name, first name, salary and department name.
SELECT emp.Last_name, emp.First_name, emp.Salary, D.Name
FROM Employee AS emp
INNER JOIN Department AS D ON emp.Department_id = D.ID
WHERE emp.Salary >=
(
SELECT AVG(e.Salary)
FROM Employee AS e
GROUP BY e.Department_id
HAVING e.Department_id = emp.Department_id
)
Can anyone please help explain the solution? Specifically, what does the 'having' clause do in this case that allows the sub-query to work? I get stuck up until that point without the having clause and I expectedly get the 'subquery returns more than 1 row' error but I am not sure how the having clause is fixing the problem.

How to write an SQL query that counts number of employees in a manager's department?

The question is as follows:
List the "manager's name" and the "number of employees" in that manager's department.
I am new to SQL and having some trouble writing a statement that queries the above statement.
This is the statement I wrote but it queries 6 employees as manager's when there should only be 3 manager's.
SELECT b.ENAME AS "Manager", COUNT(*) AS "Number of Employees"
FROM EMP e
JOIN EMP b ON b.EMPNO = e.MGR
GROUP BY b.EMPNO, b.ENAME;
The main question is how do I write it to only query the 3 manager's along with the employee count?
Thanks for the help in advance
select count(distinct e.mgr), e.ename
from emp e
where e.mgr is not null;
try using distinct and mgr is not null.

How to solve this query in SQL?

I have the following two relations:
EMP(ENO, ENAME, JOB, DATEJOB, SAL, DNO)
DEPT(DNO, DNAME, DIR)
EMP is a relation of the employees with their number ENO, their names ENAME, their job titles JOB, the dates when they get hired, their salary SAL, and the department number they are working on DNO (forgein key which references DNO in DEPT).
DEPT is a relation of the department with the number of each department DNO, the name of the department DNAME, the director of the department DIR (forgein key which references ENO).
My question is:
Write the following query in SQL.
Find the names of the employees that have the same job and the same director as 'Joe'.
My attempt was:
SELECT ENAME
FROM EMP, DEPT
WHERE EMP.DNO = DEPT.DNO
AND (DIR, JOB) IN (
SELECT DIR, JOB
FROM EMP, DEPT
WHERE ENAME = 'Joe'
AND EMP.DEPT = DEPT.DNO
)
AND ENO NOT IN (
SELECT ENO
FROM EMP, DEPT
WHERE ENAME = 'Joe'
AND EMP.DEPT = DEPT.DNO
)
I found the solution of this problem but I couldn't agree of it.
This is what I found:
SELECT ENAME
FROM EMP, DEPT
WHERE ENAME <> 'Joe'
AND EMP.DNO = DEPT.DNO
AND (DIR, JOB) = (
SELECT DIR, JOB
FROM EMP, DEPT
WHERE ENAME = 'Joe'
AND EMP.DEPT = DEPT.DNO
)
The thing is, we have to not consider 'Joe' in the result. But which 'Joe'?
It looks like there's a potential for a "director" to head multiple departments. At least, the information model doesn't seem to be anything to restrict that (i.e. no unique constraint on DIR)
Presumably, we identify employee 'Joe' by finding the tuples(s) in EMP with ENAME attribute equal to 'Joe'.
And presumably, we would identify Joe's "director" by getting the value of the DIR attribute from the DEPT relation.
If we wanted employees in the "same department" as Joe, we could just use the value of the DNO attribute,... but the requirement says "same director". So, just in case the same director heads multiple departments, we'll get all the departments headed by that director.
Then, it's a simple matter of getting all of the employees in those departments, and check for a "job" that matches Joe's "job".
SELECT e.ENAME
FROM EMP j
JOIN DEPT i
ON i.DNO = j.DNO
JOIN DEPT d
ON d.DIR = i.DIR
JOIN EMP e
ON e.DNO = d.DNO
AND e.JOB = j.JOB
WHERE j.ENAME = 'Joe'
Again, if we wanted only the employees in the "same department" as Joe, we could dispense with one of those references to DEPT. The result from this would be different, if Joe's director heads another department, and there's an employee in that other department has the same job... that employee would be excluded from this query:
SELECT e.ENAME
FROM EMP j
JOIN DEPT i
ON i.DNO = j.DNO
-- JOIN DEPT d
-- ON d.DIR = i.DIR
JOIN EMP e
-- ON e.DNO = d.DNO
ON e.DNO = i.DNO
AND e.JOB = j.JOB
WHERE j.ENAME = 'Joe'
If there's a requirement to exclude Joe from the resultset, then we could add another predicate to the WHERE clause. If we don't assume that ENAME can't have a NULL value...
AND ( e.ENAME IS NULL OR e.ENAME <> 'Joe')
You're correct in that the second solution is wrong. If there are two 'Joe's it won't work right. That's why you should exclude based on the unique ENO instead of the non-unique name. The first query won't work for the same reason. In order to be certain, you can't select either just by names or titles or departments, because those can be duplicate. We have three Chris programmers in our department.
Also, that join syntax is obsolete because it can cause confusion to the database in certain circumstances. Please see http://www.w3schools.com/sql/sql_join_inner.asp for an explanation of the current syntax.
The comma style of join you are using has been obsolete for a long time. I think the below is what you're after. The idea is to join a table to its self. This is done by giving the table aliases- source and twin here.
SELECT twin.ENAME
FROM EMP AS source
JOIN EMP AS twin ON twin.DNO = source.DNO AND twin.JOB = source.JOB
WHERE source.ENAME = 'Joe' AND source.ENO <> target.ENO

SQL: Recursive query

I've been trying to figure out how to determine how many employees have been hired after a specific employee named Blake. I want to use a recursive query. I have tried the following query to no avail:
Select E.Ename, E.Hiredate
From EMPLOYEES E, EMPLOYEES B
Where e.Hiredate = b.Hiredate
and e.Hiredate > b.Hiredate
and b.Ename = 'blake';
My thinking was that I join the Employees table to itself via 'e.Hiredate = b.Hiredate', what am I missing?
Your query would have worked if you didn't have both
e.Hiredate = b.Hiredate
and e.Hiredate > b.Hiredate
I hope you can see how the 2 values cannot ̲*s̲i̲m̲u̲l̲t̲a̲n̲e̲o̲u̲s̲l̲y̲* be equal and unequal!!
Select E.Ename, E.Hiredate
From EMPLOYEES E, EMPLOYEES B
Where e.Hiredate > b.Hiredate
and b.Ename = 'blake';
Of course, since you are asking a fairly basic 101 question, I assume only ONE employee can be named 'blake' (i.e. Ename is a unique identifier), otherwise there are other logical holes to pick.
Since you're starting in SQL, I would also advise you to use ANSI joins instead of the table-list (comma) form, which would look like this:
Select E.Ename, E.Hiredate
From EMPLOYEES E
JOIN EMPLOYEES B on e.Hiredate > b.Hiredate
WHERE b.Ename = 'blake';
Quick and dirty:
SELECT Ename, Hiredate
FROM employees
WHERE hiredate > (SELECT TOP 1 hiredate FROM employees WHERE ename = 'blake')
select e.*
from employees e
where hiredate > (select max(hiredate)
from employees
where ename = 'blake');
The max() in the inner query is necessary to ensure that only a single row is returned, even if there are more employees with that name

SQL query how to print out manager name?

I need to create a query to display employee name and number along with their super's name and super number. Listing should also include employees who don't have any supervisor.
Select e.ename,e.empno,super.ename,super from emp e;
I don't know how to print out the manager/supervisor name, i just need that.
Join the table to itself using an outer join:
select e.ename, e.empno, super.ename, super.empno
from emp e
left join emp super on super.empno = e.super_empno
The left join will still return rows from emp that do not have a super defined.
EDIT
Due to OP's comment, here's how to do it without a join (using a nasty correlated sub-query):
select
ename,
empno,
(select super.ename from emp where empno = e.super_empno) as super_name,
super_empno
from emp e;