Finding the max after Counting with Specific Conditions - sql

I am trying to find the department with the maximum amount of null assigned.
Here is the table Class:
Dept Assigned
CSCE
CSCE
ELEG 4
ELEG
MATH
ELEG
So since CSCE and ELEG have the largest amount of null assigned, I want to output.
Dept Max(Count)
CSCE 2
ELEG 2
Here is what I have:
Select Dept, Max(Countt)
from (Select Dept, Count(Dept) as Countt
from Class
where assigned is null group by Dept
);
However, it is outputting the count for all the Dept including Math. How can I fix that?
I am using Oracle.

You can use window functions for this:
select d.Dept, cnt
from (select c.Dept, Count(*) as cnt,
rank() over (order by count(*) desc) as seqnum
from Class c
where c.assigned is null
group by c.Dept
) d
where seqnum = 1;

One other way:
select count(*), dept from table
where assigned is null
group by dept
having count(*) = (select max(c) from (select count(*) as c from table
where assigned is null
group by dept) as t)

Related

SQL oracle: Need to display a query.

so i have 3 tables linked together named office, employee, and dependent.
office: Oid (PK), officeName
employee: EID(PK), Fname, Lname, JobTitle, Salary, DOH, Gender, DOB, OID(FK1), Supervisor(FK2)
Dependent: DID(PK), Fname, Lname, Gender, EID(FK1)
Here is the link to the picture of the tables:
http://classweb2.mccombs.utexas.edu/mis325/class/hw/hw12a.jpg
I need to display concatenated name and EID of 5 employees with the largest number of dependents, if there is a tie for the five largest, then I need to display all of the tying employees.
I am confused on how to begin. please help :)
thank you in advance
Just break down the problem:
How many dependents an EID has:
SELECT EID, COUNT(*) AS C
FROM Dependent
GROUP BY EID
Add a rank
SELECT EID, C, RANK() OVER (ORDER BY C DESC)
FROM (
SELECT EID, COUNT(*) AS C
FROM Dependent
GROUP BY EID
) S
We want the first 5
SELECT EID
FROM (
SELECT EID, C, RANK() OVER (ORDER BY C DESC) AS R
FROM (
SELECT EID, COUNT(*) AS C
FROM Dependent
GROUP BY EID
) S
) S2
WHERE R <= 5
Now ask for what you want:
SELECT * -- or whatever
FROM Employee
WHERE EID IN (
SELECT EID
FROM (
SELECT EID, C, RANK() OVER (ORDER BY C DESC) AS R
FROM (
SELECT EID, COUNT(*) AS C
FROM Dependent
GROUP BY EID
) S
) S2
WHERE R <=5
) S3
I suggest you run each step and make sure it gives you the expected results.
Ummm I would try something like this:
Select TOP 5
a.FNAME,
a.LNAME,
a.EID,
Count(b.EID) as Dependents
FROM employee a
LEFT JOIN dependent b on a.EID = b.EID
group by 1,2,3 order by Dependents desc

How to select first and last record from ordered query without UNION, INTERSECT etc

So, I admit it was one of my exam tasks yesterday and I failed to deal with it...
I had simple database of people with their name, salary and function (A, B, C, D, E and F) and I had to select functions that have the biggest and the lowest avg salary. I had also to ignore function C.
Example of database:
name salary function
Mike 100 A
John 200 F
Jenny 500 B
Fred 400 B
... 250 C
... 800 D
... 100 E
... 350 E
... 450 F
... 250 A
... 500 B
Example of result:
function avg salary
A 300
C 600
I know how to do it using UNION as in oracle I can group by function order by salary, union that with order by salary desc and for example fetch 1 rows only in both selects. I could have used WHERE but it's impossible to use WHERE with aggregation (like AVG(salary)), but how to do it in single query without UNION, MINUS or INTERSECT?
Similar to #vkp's approach, but without the join back to the base table:
select function, avg_salary
from (
select function, avg(salary) as avg_salary,
rank() over (order by avg(salary)) as rnk_asc,
rank() over (order by avg(salary) desc) as rnk_desc
from tablename
group by function
)
where rnk_asc = 1 or rnk_desc = 1;
F AVG_SALARY
- ----------
D 800
A 175
The two rank() calls put each function/average in order:
select function, avg(salary) as avg_salary,
rank() over (order by avg(salary)) as rnk_asc,
rank() over (order by avg(salary) desc) as rnk_desc
from tablename
group by function;
F AVG_SALARY RNK_ASC RNK_DESC
- ---------- ---------- ----------
D 800 6 1
B 4.7E+02 5 2
F 325 4 3
C 250 3 4
E 225 2 5
A 175 1 6
That forms the inline view; the outer query then just selects the rows ranked 1 in either of the generated columns, which is D and A here.
If you had two functions with the same average salary then they would get the same rank, and both ranked as 1 then you'd see both; so you can get more than two results. That may be what you want. If not you can avoid it by defining how to break ties, either with rank() or dense_rank().
You could use rank function (use dense_rank if there can be ties in averages) to order rows by their average salary. Then select the highest and lowest ranked rows.
select t1.function, avg(t1.salary)
from (select
rank() over(order by avg(salary) desc) rnk_high
,rank() over(order by avg(salary)) rnk_low
,function
from tablename
group by function) t
join tablename t1 on t.function = t1.function
where rnk_high = 1 or rnk_low = 1
group by t1.function
If you want to return exactly one min/max row you probably get a better plan when you avoid two different ORDER BY:
select function, avg_salary
from (
select function, avg(salary) as avg_salary,
ROW_NUMBER() over (order by avg(salary)) as rnk_asc,
COUNT(*) over () as cnt
from tablename
group by function
)
where rnk_asc = 1 or rnk_asc = cnt;
Caution, RANK will fail if there are two rows with the same MAX value (no row where rnk_asc = cnt).
Can you use subquery in Oracle ?
try this
Select z.Function from
(Select Function, Avg(Salary) avgSal
from tableName
group By function) z
Where z.avgSal = (Select Max(z0.avgSal)
from (Select Avg(Salary) avgSal
from tableName
group By function) z0)
Or z.avgSal = (Select Min(z1.avgSal)
from (Select Avg(Salary) avgSal
from tableName
group By function) z1)

Finding department having maximum number of employee

I have a table employee
id name dept
1 bucky shp
2 name shp
3 other mrk
How can i get the name of the department(s) having maximum number of employees ? ..
I need result
dept
--------
shp
SELECT cnt,deptno FROM (
SELECT rank() OVER (ORDER BY cnt desc) AS rnk,cnt,deptno from
(SELECT COUNT(*) cnt, DEPTNO FROM EMP
GROUP BY deptno))
WHERE rnk = 1;
Assuming you are using SQL Server and each record representing an employee. So you can use window function to get the result
WITH C AS (
SELECT RANK() OVER (ORDER BY dept) Rnk
,name
,dept
FROM table
)
SELECT TOP 1 dept FROM
(SELECT COUNT(Rnk) cnt, dept FROM C GROUP BY dept) t
ORDER BY cnt DESC
With common table expressions, count the number of rows per department, then find the biggest count, then use that to select the biggest department.
WITH depts(dept, size) AS (
SELECT dept, COUNT(*) FROM employee GROUP BY dept
), biggest(size) AS (
SELECT MAX(size) FROM depts
)
SELECT dept FROM depts, biggest WHERE depts.size = biggest.size
Based on one of the answer, Let me try to explain step by step
First of all we need to get the employee count department wise. So the firstly innermost query will run
select count(*) cnt, deptno from scott.emp group by deptno
This will give result as
Now out of this we have to get the one which is having max. employee i.e. department 30.
Also please note there are chances that 2 departments have same number of employees
The second level of query is
select rank() over (order by cnt desc) as rnk,cnt,deptno from
(
select count(*) cnt, deptno from scott.emp group by deptno
)
Now we have assigned ranking to each department
Now to select rank 1 out of it. we have a simplest outer query
select * from
(
select rank() over (order by cnt desc) as rnk,cnt,deptno from
(
select count(*) cnt, deptno from scott.emp group by deptno
)
)
where rnk=1
So we have the final result where we got the department which has the maximum employees. If we want the minimum one we have to include the department table as there are chances there is a department which has no employees which will not get listed in this table
You can ignore the scott in scott.emp as that is the table owner.
The above SQL can be practised at Practise SQL online

Top 2 Salary Grouped By Department

Below is the table I am referring to.
I want to find ou the 2 Employees in each department with highest salary.
Further to the above answer, if there are ties (multiple employees sharing the same salary), you can use the following to bring them all through instead of just picking two at random (which is what the ROW_NUMBER clause will do)
SELECT *
FROM (
SELECT *, DENSE_RANK() OVER (PARTITION BY Dept ORDER BY Salary DESC) AS rn
FROM MyTable ) t
WHERE t.rn <= 2
Use ROW_NUMBER() to get the top salaries per Department, then select the first two records from each departmental partiton:
SELECT *
FROM (
SELECT *, ROW_NUMBER() OVER (PARTITION BY Dept ORDER BY Salary DESC) AS rn
FROM MyTable ) t
WHERE t.rn <= 2

Get MAX value of count of each dept after group by clause on dept and grade

My query gets count of employee for each dept for each grade .
select dept , grade , count(1) CNT
from mytable
group by dept , grade
order by dept , cnt desc;
now i need from that the grades getting max count of each dept .
output should be
dept grades MAX(count)
how can i do that?
Thanks
The best way to do this is using the row_number() function:
select dept, grade, cnt
from (select dept, grade, count(*) as cnt,
row_number() over (partition by dept order by count(*) desc) as seqnum
from mytable t
group by dept, grade
) t
where seqnum = 1