ALL keyword in Oracle SQL - sql

I want the empno who is working on at least all the same projects on which empno 101 is working.
I tried following query but failed:
SELECT EMPNO
FROM EMPLOYEE
WHERE PROJECTNO= ALL(SELECT PROJECTNO
FROM EMPLOYEE
WHERE EMPNO=101);
Empno 101 IS working on comp134 and comp90
and empno 103 is also working on both these projects
but I get answer as no rows selected for following table.
projectno empno
--------- ------
comp134 101
comp90 101
comp90 103
comp14 104
comp213 103
comp134 103
comp14 108
comp90 104

For Exact Match:
SELECT EMPNO
FROM EMPLOYEE E1
WHERE EXISTS
(
SELECT 'x' FROM EMPLOYEE E2
WHERE E2.EMPNO=101 AND E1.PROJECTNO = E2.PROJECTNO
)
MINUS
SELECT EMPNO
FROM EMPLOYEE E1
WHERE NOT EXISTS
(SELECT 'x' FROM EMPLOYEE E2
WHERE E2.EMPNO=101 AND E1.PROJECTNO = E2.PROJECTNO)
For Atleast All of it Also For Exact Match
SELECT EMPNO
FROM EMPLOYEE e
JOIN (SELECT PROJECTNO,count(1) OVER () AS ct
FROM EMPLOYEE
WHERE EMPNO=101) my_list
ON (e.PROJECTNO = my_list.PROJECTNO AND e.EMPNO <> 101)
GROUP BY EMPNO
HAVING count(*) = MAX(my_list.ct)

This sounds like a kind of Relational Division:
with cte as
( select PROJECTNO
from EMPLOYEE
WHERE EMPNO=101
)
SELECT EMPNO
FROM EMPLOYEE as e
join cte
on e.PROJECTNO = cte.PROJECTNO
group by EMPNO
HAVING count(*)
= (select count(*) from cte)

try this
select `projectno` from
( select `projectno`, count(`empno`) as counts from EMPLOYEE
group by `empno`
order by counts desc
limit 1)t ;
or even simpler like that
select `projectno`
from EMPLOYEE
group by `empno`
order by count(`empno`) desc
limit 1
DEMO HERE

Related

Find the dept where more than avg. no of emps are working SQL

List the name of the dept where more than avg. no of emps are working
Table emp_demo
emp_id dname
1 d1
2 d2
3 d3
4 d2
5 d1
6 d2
There are 2 employees in D1, 3 employees in D2 and 1 employee in D3.
Average number of employees will be (2+3+1/3) = 2 employees
So the department with more than avg number of employees here will be D2 (with 3 employees).
Query code made by me:
select *
from emp_demo
group by dname
having count(emp_id) > AVG(count(emp_id))
Error
Cannot perform an aggregate function on an expression containing an aggregate or a subquery.
The error is caused by SQL Server not allowing an aggregate function to contain another aggregate function.
One way you can try to use CTE with subquery JOIN.
;with cte as (
SELECT dname,COUNT(emp_id) cnt
FROM emp_demo
GROUP BY dname
)
SELECT t1.*
FROM cte t1
JOIN (SELECT avg(cnt) avgCnt FROM cte) t2
ON t1.cnt > t2.avgCnt
sqlfiddle
First, calculate the average number of emp_id using a variable. This has a subquery that calculates the count per dname then the main query runs an average over that.
The second part of the query is an information-only line telling you what the average it has worked out is. Not needed if you don't want it.
The third part runs the count again, but filtering out dname entries that are not greater than the #avg_emps variable calculated at the start:
declare #avg_emps int = (
select
avg(emp_count) as avg_emp_count
from (
select
dname
,count(emp_id) as emp_count
from dbo.foo
group by dname
) as count_emps
)
select 'Average employees per department is: ' + cast(#avg_emps as varchar(10));
select
dname
from dbo.foo
group by dname
having count(emp_id) > #avg_emps;
Use a CTE which returns the average numbers of employees in each department:
with cte as (
select dname, count(*) counter
from emp_demo
)
select dname
from cte
where counter > (select avg(counter) from cte)
This should work without use of any variables:
SELECT *
FROM emp_demo
GROUP by dname
HAVING count(emp_id) > (
SELECT AVG(r1.c1)
from (
SELECT count(emp_id)) as c1
FROM emp_demo
GROUP by dname
) as r1
)

Query: dept name with highest no of emps , error: Cannot perform an aggregate function on an expression containing an aggregate or a subquery

List the name of dept where highest no of emps are working
Table
emp_id dname
1 D1
2 D2
3 D1
4 D2
5 D2
6 D3
7 D2
Query
select dname from emp_demo e1 having
count(emp_id) =
(select max(count(emp_id)) from emp_demo e2
group by dname )
Error
Cannot perform an aggregate function on an expression containing an aggregate or a subquery.
Expected output
D1 has 2 employees in it, D2 has 4 employees and D3 has 1 employee in it. So we should get department number D2 since it has maximum number of employees in it.
You can use window function :
select dname
from (select dname, dense_rank() over (order by count(*) desc) as seq
from table t
group by dname
) t
where seq = 1;
DENSE_RANK() will return one or more dept which are having highest same no_of_employee's.
You can use the count() function in the following manner.
; WITH cte
AS (
SELECT dname
,count(emp_id) AS TotEmpCount
FROM EmpDept
GROUP BY dname
)
SELECT TOP 1 *
FROM cte
ORDER BY TotEmpCount DESC
Live db<>fiddle demo.
Simply use top (1) and group by:
select top (1) dname
from emp_demo
group by dname
order by count(*) desc;
You can use below simple query.
select dname, max(count(1)) from emp_demo
group by dname;

Explain how to find the 3rd MAX salary in the emp table

Anyone will please explain me the runtime execution of the below query:-
select distinct sal
from emp e1
where 3 = (select count(distinct sal)
from emp e2
where e1.sal <= e2.sal);
select distinct sal
from emp e1
where 3 = (
select count(distinct sal)
from emp e2
where e1.sal <= e2.sal
)
It's a correlated query which means the subquery runs for each row of the outer query:
The subquery returns the count of distinct salaries that are greater than or equal to the given salary
for example there are following values in emp table:
10
20
30
40
Say the Outer query is at row with sal = 40. The count returned by the subquery will be 1.
for sal = 30, count = 2
for sal = 20, count = 3
for sal = 10, count = 4
so only row matching your criteria is row with sal = 20 which is what you wanted.
A better way can be using rank:
select distinct sal
from (
select t.*,
dense_rank() over (
order by salary desc
) as rnk
from your_table t
) t
where rnk = 3;
I think a shorter way is when you use the (rather new) function NTH_VALUE:
SELECT DISTINCT NTH_VALUE(salary, 3) OVER ()
FROM your_table;

Max and Min sal with employee name in one query

I'm working on one SQL query.
Table name: employees.
I want to get the MAX and MIN sal with their employee names in SQL.
I know how to do with either MAX or MIN. But how can we do it both in one query?
I need a single row output like below:
e1.name AS MaxName, MAX(e1.sal) AS MaxSalary, e2.name AS MinName, MIN(e2.sal) AS MinSalary
In a single select:
SELECT MIN( salary ) AS MinSalary,
MIN( name ) KEEP ( DENSE_RANK FIRST ORDER BY salary ASC ) AS MinName,
MAX( Salary ) AS MaxSalary,
MAX( name ) KEEP ( DENSE_RANK LAST ORDER BY salary ASC ) AS MaxName
FROM Employees;
Two ways:
Using Analytic function:
SQL> SELECT MIN(ename) KEEP (DENSE_RANK FIRST ORDER BY sal) min_name,
2 MIN(sal) AS min_sal,
3 MAX(ename) KEEP (DENSE_RANK LAST ORDER BY sal) AS max_name,
4 MAX(sal) AS max_sal
5 FROM emp;
MIN_NAME MIN_SAL MAX_NAME MAX_SAL
---------- ---------- ---------- ----------
SMITH 800 KING 5000
Using an In-line view:
SQL> WITH DATA AS
2 ( SELECT MIN(sal) min_sal, MAX(sal) max_sal FROM emp
3 )
4 SELECT
5 (SELECT e.ename FROM DATA t, emp e WHERE e.sal = t.min_sal AND ROWNUM =1
6 ) min_name,
7 (SELECT t.min_sal FROM DATA t, emp e WHERE e.sal = t.min_sal AND ROWNUM =1
8 ) min_sal,
9 (SELECT e.ename FROM DATA t, emp e WHERE e.sal = t.max_sal AND ROWNUM =1
10 ) max_name,
11 (SELECT t.max_sal FROM DATA t, emp e WHERE e.sal = t.max_sal AND ROWNUM =1
12 ) max_sal
13 FROM dual;
MIN_NAME MIN_SAL MAX_NAME MAX_SAL
---------- ---------- ---------- ----------
SMITH 800 KING 5000
Assuming that you are using Oracle, try this. Here first we are getting rownumber in ascending and descending order and then doing a cross join.
with employee(id,name,sal) as
(select 1,'a',1000 from dual union all
select 3,'c',1500 from dual union all
select 2,'b',2000 from dual) --temp table to recreate the scenario
, enew as(
select e.*,row_number() over (order by sal) as salasc,row_number() over (order by sal desc) as saldesc from employee e
) --temp table to find the rownumber in ascending and descending order
--original query
select * from (select id as minsalid,name as minsalempname,sal as minsal from enew
where salasc=1)
cross join
(select id as maxsalemp,name as maxsalempname,sal as maxsal from enew
where saldesc=1)
The following solution works for MySQL, which was one of the tags you originally had when you posted your question.
You can perform a CROSS JOIN of the employees table against itself to find the max name/salary with a query which finds the min name/salary.
SELECT e1.name AS MaxName, MAX(e1.sal) AS MaxSalary,
e2.name AS MinName, MIN(e2.sal) AS MinSalary
FROM employees e1 CROSS JOIN employees e2
Click the link below for a running demo. I actually include the name/salary pairs, though you can remove the names if you don't want them there.
SQLFiddle
Try something like:
select max(sal), min(sal), employee_id
from employees
group by employee_id;
After that you can join it to get the name. Maybe you can group by name and id too.

Select all the people that have the same salary

I have problems finding a solution to an SQL query. This is probably a very obvious beginner question but I can't seem to get the results that I'm after. I have a table that looks something like the following:
|Name |Station|Salary|
|Bob |1 |2000 |
|Steve|2 |1750 |
|Mark |3 |2050 |
|Lisa |4 |2200 |
|Hans |5 |2000 |
I would like to select the names of the people in this table that have the same salary. The result should of course be Bob and Hans.
If you join the table against itself on Salary but where the names are separate then this should give you any matching salaried people:
SELECT s1.Name, s1.Station, s1.Salary
FROM Staff s1
INNER JOIN Staff s2 ON s1.Salary = s2.Salary AND s1.Name <> s2.Name
Here's a SQLFiddle to show it in action
SELECT Name
FROM table1
WHERE Salary IN (
SELECT Salary
FROM table1
GROUP BY Salary
HAVING COUNT(*) > 1
)
If you determine the salary bands which have more than one employee, you can then join back to it as a derived table:
SELECT e.Name, e.Station
FROM Employee e
INNER JOIN
(
SELECT Salary
FROM Employee
GROUP BY Salary
HAVING COUNT(*) > 1
) grp ON e.Salary = grp.Salary;
SqlFiddle here
Most databases support window functions. The simple method to do this is to count the number of people that have a given salary. Then choose those people. Here is an easy method:
select t.*
from (select t.*, count(*) over (partition by salary) as salarycnt
from table t
) t
where salarycnt > 1
order by salary;
TRY THIS:
SELECT E1.Name, E1.Salary
FROM Employee E1, Employee E2
WHERE E1.Salary = E2.Salary
AND E1.Name <> E2.Name
http://sqlfiddle.com/#!2/1e34b
Use below Query:
with datatab as
(
select 'Bob' Name, 1 Station, 2000 Salary from dual union
select 'Steve' Name, 2 Station, 1750 Salary from dual union
select 'Mark' Name, 3 Station, 2050 Salary from dual union
select 'Lisa' Name, 4 Station, 2200 Salary from dual union
select 'Hans' Name, 5 Station, 2000 Salary from dual union
select 'Test' Name, 6 Station, 1750 Salary from dual
)
SELECT NAME, sTATION, SALARY FROM DATATAB
WHERE SALARY IN
(
SELECT Salary
FROM datatab
GROUP BY Salary
HAVING COUNT(1) > 1
);
As someone suggested in Edits, The Query would be:
SELECT NAME, sTATION, SALARY FROM TABLE_NAME
WHERE SALARY IN
(
SELECT Salary
FROM TABLE_NAME
GROUP BY Salary
HAVING COUNT(1) > 1
)
Select a.name, a.salary from
(
Select count(salary) as cnt, salary from staff group by salary having count(salary) > 1
)as X
Inner join staff a on a.Salary=x.salary
order by a.salary:
Use aliases when you have to put one and the same table two or more times:
select t1.Name,
t2.Name,
t1.Salary
from MyTable t1,
MyTable t2
where t1.Station > t2.Station and -- if Station is id
-- t1.Name > t2.Name -- if Name is in fact an id
t1.Salary = t2.Salary
Try this:
select COUNT(*) as NumberOfPerson,salary from tblEmployee group by salary having COUNT(*)>1
For MySQL:
Select * from worker
where salary in (select salary from worker
group by salary
having count(1)>1);
lets say table name is: employee
select distinct e.name, e.salary from employee e, employee e1 where
e.salary = e1.salary and e.name != e1.name;
First Solution :
Select e1.name from employee e1
inner join employee e2 on e1.salary=e2.salary AND e1.name <> e2.name
Second easy solution:
Select name from employee
where salary In (Select salary from employee
group by salary
having count(*)>1)
SUPPOSE WE HAVE TABLE NAMELY AS EMP3 WHICH ONTEIN COLUMNS AS FIRST_NAME,LAST_NAME,SALRY,DEPARTMENT_ID,COMMISSION ETC.
NOW WE HAVE TO SELECT RECORDS OF EMPLOYEES WHO HAVE THE SAME SALARY.
LET'S GET OUTPUT WITH THE HELP OF SELF JOIN.
HERE WE ARE JOINING THE SAME TABLE WITH ITSELFMTO GET RECORDS WHO HAVE THE SAME SALARY.
SELECT E1.FIRST_NAME AS FN,E1.SALARY FROM EMPLOYEES E1 INNER JOIN EMPLOYEES E2 ON E1.SALARY=E2.SALARY;
Treating same table as a separate two table.
SELECT DISTINCT T.username, T.salary
FROM account T, account T
WHERE T.salary = T.salary
AND T.username <> T.username
ORDER BY salary;
Do you want the quantity of people with the same salary.
SELECT count(*) FROM table GROUP BY salary