Find the employee with max salary in his department - sql

Table structure is as below
id dept salary
1 30 2000
2 20 5500
3 30 6700
4 30 8900
5 30 9900
6 10 1120
7 20 8900
8 10 2400
9 30 2600
10 10 2999
I need the output to have two columns:
Id and Salary
Id should be unique and salary should have the max salary

Although data structure is a bit strange, the query below will give the desired result:
create table #tmp(
id numeric(10,0),
dept int,
salary numeric(10,0))
insert #tmp select 1, 30, 2000
insert #tmp select 2, 20, 5500
insert #tmp select 3, 30, 6700
insert #tmp select 4, 30, 8900
insert #tmp select 5, 30, 9900
insert #tmp select 6, 10, 1120
insert #tmp select 7, 20, 8900
insert #tmp select 8, 10, 2400
insert #tmp select 9, 30, 2600
insert #tmp select 10, 10, 2999
select * from #tmp order by dept
id dept salary
------------ ----------- ------------
6 10 1120
8 10 2400
10 10 2999
2 20 5500
7 20 8900
1 30 2000
9 30 2600
3 30 6700
4 30 8900
5 30 9900
select id, salary
from #tmp t1, (select dept=dept, salaryMax=max(salary) from #tmp group by dept) t2
where t1.dept = t2.dept
and t1.salary = t2.salaryMax
id salary
------------ ------------
7 8900
10 2999
5 9900

SELECT ID,Salary FROM TABLE_NAME WHERE SALARY =(SELECT MAX(SALARY) FROM TABLE_NAME)

SELECT a.Id, a.Salary
FROM table a
WHERE a.Salary = (SELECT MAX(Salary) FROM table
WHERE Id = a.Id)

select * from (select * from dep order by salary desc, dep, id) t
group by t.dep

Use NOT EXISTS to return an epmloyee if no other within same department has a higher salary.
select * from table t1
where not exists (select 1 from table t2
where t2.dept = t1.dept
and t2.salary > t1.salary)
Core SQL-99, will work with both Oracle and Sybase!
Alternative solution:
select * from table
where (dept, salary) = (select dept, max(salary)
from table
group by dept)
Using the following feature outside Core SQL-2003: F641, "Row and table constructors". (Don't know what Sybase and Oracle supports here...)

Using single scan:
WITH SALARIES AS (
SELECT 1 ID, 30 DEPT, 2000 SALARY FROM DUAL UNION ALL
SELECT 2 ID, 20 DEPT, 5500 SALARY FROM DUAL UNION ALL
SELECT 3 ID, 30 DEPT, 6700 SALARY FROM DUAL UNION ALL
SELECT 4 ID, 30 DEPT, 8900 SALARY FROM DUAL UNION ALL
SELECT 5 ID, 30 DEPT, 9900 SALARY FROM DUAL UNION ALL
SELECT 6 ID, 10 DEPT, 1120 SALARY FROM DUAL UNION ALL
SELECT 7 ID, 20 DEPT, 8900 SALARY FROM DUAL UNION ALL
SELECT 8 ID, 10 DEPT, 2400 SALARY FROM DUAL UNION ALL
SELECT 9 ID, 30 DEPT, 2600 SALARY FROM DUAL UNION ALL
SELECT 10 ID, 10 DEPT, 2999 SALARY FROM DUAL
)
SELECT
MAX(ID) KEEP (DENSE_RANK LAST ORDER BY SALARY) ID,
MAX(SALARY) SALARY
FROM
SALARIES
GROUP BY
DEPT;

All the below three queries worked :
select t.dept, t.salary
from
(select dept,max(salary) as m_sal from tempdb..test
group by dept)x, tempdb..test t
where x.dept = t.dept
and x.m_sal = t.salary
select dept, id, salary as m_sal
from tempdb..test t1
where salary = (select max(salary) from tempdb..test t2 where t2.dept = t1.dept)
select t1.dept,t1.salary from tempdb..test t1
inner join
(select dept,max(salary) as m_sal from tempdb..test
group by dept)x on
t1.salary=x.m_sal and
t1.dept=x.dept

Related

How to get max salary and count from employee table

I have task where I need to filter in such a way that need to print the max(salary * months) and number of times the max(salary * months) occurred.
My data:
employee_id , name , months , salary
12 , Ami , 15 , 1230
14 , Bik , 1 , 678
15 , Tom , 10 , 500
16 , Bob , 12 , 3456
17 , Wil , 1 , 9000
18 , Tim , 14 , 1239
22 , Jil , 15 , 1230
Note: the table as only 4 columns -> employee_id, name, months, salary
I have written a query where I am able to get max(salary * months)
Query #1:
select
max(msal)
from
(select
employee_id,
name,
salary,
months,
(salary * months) as msal
from
employee);
Query #2:
select
e1.employee_id,
e1.months,
e1.salary,
e2.employee_id,
(e2.salary * e2.months) as earnings
from
employee e1
join
employee e2 on e1.employee_id = e2.employee_id;
Query #3:
select
emp,earnings
from
(
select
e1.employee_id as emp,
e1.months,
e1.salary,
e2.employee_id,
(e2.salary * e2.months) as earnings
from
employee e1
join employee e2 on e1.employee_id = e2.employee_id
)
order by
earnings desc;
I calculated on paper these details:
15 * 1230 -> 18450
1 * 678 -> 678
10 * 500 -> 5000
12 * 3456 -> 41472
1 * 9000 -> 9000
14 * 1239 -> 17346
15 * 1230 -> 18450
According my analysis my output should be: 41472 1
41472-> max(salary * months)
1 -> occurred twice
Here's one option:
Sample data:
SQL> with emp (employee_id, name, months, salary) as
2 (select 12, 'ami', 15, 1230 from dual union all
3 select 14, 'bik', 1 , 678 from dual union all
4 select 15, 'tom', 10, 500 from dual union all
5 select 16, 'bob', 12, 3456 from dual union all
6 select 17, 'wil', 1 , 9000 from dual union all
7 select 18, 'tim', 14, 1239 from dual union all
8 select 22, 'jil', 15, 1230 from dual
9 ),
Query begins here: rank values in descending order ...
10 temp as
11 (select salary * months max_value,
12 count(*) cnt,
13 rank() over (order by salary * months desc) rnk
14 from emp
15 group by salary * months
16 )
17 select max_value, cnt
18 from temp
19 where rnk = 1; --> ... and, finally, fetch row(s) that rank as the highest
MAX_VALUE CNT
---------- ----------
41472 1
SQL>
Although you didn't ask for it, but - such an approach is good because you can easily get - for example:
the second highest value simply by modifying the where clause to
where rnk = 2
top 3 values
where rnk <= 3
etc.
You want to look at salary * month results, count their occurence and only show the top figure. So, group by salary * month, count and take the top row:
select salary * month, count(*)
from employee
group by salary * month
order by salary * month desc
fetch first row only;
Finally I was able to write a Query
Incase any efficient way of writing Query. Please provide your solution
Query :
SELECT
msal,
COUNT(*)
FROM
(
SELECT
months * salary AS msal
FROM
employee_salary
WHERE
( months * salary ) IN (
SELECT
MAX(months * salary)
FROM
employee_salary
)
)
GROUP BY
msal;

Sum of multiple union select showing every result and total

My SQL shows the count of records in multiple tables
SELECT 'S_MH_DSC_Abandoned' Table_N ,COUNT(*) Count FROM S_MH_DSC_Abandoned
UNION SELECT 'S_MH_DSC_ExclAbandoned' Table_N, COUNT(*) Count FROM S_MH_DSC_ExclAbandoned
UNION SELECT 'S_MH_Private_All' Table_N, COUNT(*) Count FROM S_MH_Private_All
I want to show this plus the total of the values in the last column as above.
I have tried
Select 'Sum Total' Table_N, sum(a) as Total from
(
SELECT 'S_MH_DSC_Abandoned',COUNT(*) a FROM S_MH_DSC_Abandoned
UNION SELECT 'S_MH_DSC_ExclAbandoned', COUNT(*) a FROM S_MH_DSC_ExclAbandoned
UNION SELECT 'S_MH_Private_All', COUNT(*) a FROM S_MH_Private_All
)
But only get the total without the other values.
How can I get both the working counts and the total?
This is using QGIS flavour of SQL - https://sqlite.org/lang.html
I don't use SQLite.
However, reviewing its documentation, it looks as if it doesn't know ROLLUP (which comes handy in such a case):
SQL> with temp (job, sumsal) as
2 (select 'Clerk', sum(sal) from emp where job = 'CLERK' union all
3 select 'Mgr' , sum(sal) from emp where job = 'MANAGER' union all
4 select 'Sale' , sum(sal) from emp where job = 'SALESMAN'
5 )
6 select job, sum(sumsal) sumsal
7 from temp
8 group by rollup (job);
JOB SUMSAL
----- ----------
Clerk 4150
Mgr 8275
Sale 5600
18025
SQL>
Therefore, simulate it with a union:
SQL> with temp (job, sumsal) as
2 (select 'Clerk', sum(sal) from emp where job = 'CLERK' union all
3 select 'Mgr' , sum(sal) from emp where job = 'MANAGER' union all
4 select 'Sale' , sum(sal) from emp where job = 'SALESMAN'
5 )
6 select job, sumsal
7 from temp
8 union
9 select 'Total', sum(sumsal)
10 from temp;
JOB SUMSAL
----- ----------
Clerk 4150
Mgr 8275
Sale 5600
Total 18025
SQL>
Using your query:
with temp (tname, cnt) as
(SELECT 'S_MH_DSC_Abandoned' , COUNT(*) FROM S_MH_DSC_Abandoned union all
SELECT 'S_MH_DSC_ExclAbandoned', COUNT(*) FROM S_MH_DSC_ExclAbandoned union all
SELECT 'S_MH_Private_All' , COUNT(*) FROM S_MH_Private_All
)
select tname, cnt
from temp
union
select 'Total', sum(cnt)
from temp;

How to extract the number of subordinates from manager_id in the same table?

I've two columns: one with employee_id and one with manager_id
Apart from the President with employee_id 100 who doesn't have a manager (so manager_id is null) the rest have managers. For example, the President is the manager for two people with manager_id of 100. How to count and place it in this way:
employee_id 100 (column1) has 2 subordinates (column2)?
tried count, sum ,case, subquery and did't work
select employee_id,
manager_id,
first_name,
last_name,
case when employee_id = manager_id then count(employee_id) end,
count(manager_id)
from employees
--where manager_id is not null
group by manager_id,
employee_id,
first_name,
last_name
--having sum(manager_id) > 5
order by employee_id;
I expect to have 1st column as employee_id and second as the counted subordinates per employee_id.
Use a correlated hierarchical query:
Oracle Setup:
CREATE TABLE employees ( employee_id, manager_id ) AS
SELECT 100, NULL FROM DUAL UNION ALL
SELECT 101, 100 FROM DUAL UNION ALL
SELECT 102, 101 FROM DUAL UNION ALL
SELECT 103, 102 FROM DUAL UNION ALL
SELECT 104, 103 FROM DUAL UNION ALL
SELECT 105, 101 FROM DUAL UNION ALL
SELECT 106, 105 FROM DUAL UNION ALL
SELECT 107, 106 FROM DUAL UNION ALL
SELECT 108, 101 FROM DUAL UNION ALL
SELECT 109, 108 FROM DUAL;
Query:
SELECT employee_id,
(
SELECT COUNT(*)
FROM employees s
START WITH s.manager_id = e.employee_id
CONNECT BY PRIOR employee_id = manager_id
) AS num_subordinates
FROM employees e
Output:
EMPLOYEE_ID | NUM_SUBORDINATES
----------: | ---------------:
100 | 9
101 | 8
102 | 2
103 | 1
104 | 0
105 | 2
106 | 1
107 | 0
108 | 1
109 | 0
db<>fiddle here
if i understand your question, you could also do it with a simple Group by
this will count only the subordinates not the whole hierarchy
with tab as(
select 1 as emp_id, null as man_id from dual union all
select 2 as emp_id, 1 as man_id from dual union all
select 3 as emp_id, 1 as man_id from dual union all
select 2 as emp_id, null as man_id from dual union all
select 5 as emp_id, 2 as man_id from dual
)
select man_id as employee_id
, count(1) as cnt
from tab
where man_id is not null
group by man_id
EMPLOYEE_ID | CNT
----------: | --:
2 | 1
1 | 2
db<>fiddle here
Try this:
-- data preparation
WITH EMPS AS
(
SELECT 1001 AS EMP_ID, 'emp11' AS POS, 100 AS MGR_ID FROM DUAL UNION ALL
SELECT 1002 AS EMP_ID, 'emp12' AS POS, 100 AS MGR_ID FROM DUAL UNION ALL
SELECT 1003 AS EMP_ID, 'emp13' AS POS, 100 AS MGR_ID FROM DUAL UNION ALL
SELECT 2001 AS EMP_ID, 'emp21' AS POS, 200 AS MGR_ID FROM DUAL UNION ALL
SELECT 2002 AS EMP_ID, 'emp22' AS POS, 200 AS MGR_ID FROM DUAL UNION ALL
SELECT 100 AS EMP_ID, 'mgr1' AS POS, 1 AS MGR_ID FROM DUAL UNION ALL
SELECT 200 AS EMP_ID, 'mgr2' AS POS, 1 AS MGR_ID FROM DUAL UNION ALL
SELECT 1 AS EMP_ID, 'President' AS POS, NULL AS MGR_ID FROM DUAL )
-- Your actual query starts from here
SELECT
EE.EMP_ID,
EE.POS,
EE.MGR_ID,
CASE
WHEN EC.CNT IS NULL THEN 0
ELSE EC.CNT
END AS CNT
FROM
EMPS EE
LEFT JOIN (
SELECT
MGR_ID,
COUNT(1) AS CNT
FROM
EMPS
GROUP BY
MGR_ID
) EC ON EE.EMP_ID = EC.MGR_ID
ORDER BY
EE.EMP_ID;
Please add the other condition according to your needs.
DB Fiddle demo
Try this, use a select within the select
select emp.employee_id,
emp.manager_id,
emp.first_name,
emp.last_name,
(SELECT SUM(employees.employee_id) FROM employees where employees.manager_id=emp.employee_id) as subordinates,
count(manager_id)
from employees emp

How to Get Set of Second Highest Values?

Suppose I have the following table:
employee_id salary
34 100
22 49
19 49
29 30
17 22
And I want to return the set of employees with the second highest salaries (when there are ties), as follows:
employee_id salary
22 49
19 49
How would I do that?
Use DENSE_RANK:
SELECT employee_id, salary
FROM
(
SELECT employee_id, salary, DENSE_RANK() OVER (ORDER BY salary DESC) dr
FROM yourTable
) t
WHERE dr = 2;
You can use nested query.
Steps taken :
Get all salary values ( sort it and obtain 2nd highest value ) :
SELECT salary FROM employee GROUP BY 1 ORDER BY 1 DESC limit 1 OFFSET 1;
OR can be written as :
SELECT salary FROM employee GROUP BY employee_id ORDER BY employee_id DESC limit 1 OFFSET 1;
Now use the query within employee table
SELECT * FROM employee where salary=(SELECT salary FROM employee GROUP BY 1 ORDER BY 1 DESC limit 1 OFFSET 1);
this can be done also in using query below,
scenario 1: Output two records
WITH employee
AS (
SELECT 34 emp_id, 100 rate FROM DUAL
UNION
SELECT 22 emp_id, 49 rate FROM DUAL
UNION
SELECT 19 emp_id, 49 rate FROM DUAL
UNION
SELECT 29 emp_id, 30 rate FROM DUAL
UNION
SELECT 17 emp_id, 22 rate FROM DUAL),
emp_rate_cnt AS
(SELECT rownum rown, rate, same_rate_count
FROM (SELECT rate, count(1) same_rate_count
FROM employee
GROUP BY rate
ORDER BY rate DESC))
SELECT *
FROM employee a
WHERE exists (SELECT 1
FROM emp_rate_cnt b
WHERE b.rate = a.rate
AND b.rown = 2
AND b.same_rate_count > 1);
scenario 2: Output no records
WITH employee
AS (
SELECT 34 emp_id, 100 rate FROM DUAL
UNION
SELECT 22 emp_id, 49 rate FROM DUAL
UNION
SELECT 19 emp_id, 50 rate FROM DUAL
UNION
SELECT 29 emp_id, 30 rate FROM DUAL
UNION
SELECT 17 emp_id, 22 rate FROM DUAL),
emp_rate_cnt AS
(SELECT rownum rown, rate, same_rate_count
FROM (SELECT rate, count(1) same_rate_count
FROM employee
GROUP BY rate
ORDER BY rate DESC))
SELECT *
FROM employee a
WHERE exists (SELECT 1
FROM emp_rate_cnt b
WHERE b.rate = a.rate
AND b.rown = 2
AND b.same_rate_count > 1);
I hope this is the easiest of all. Use rownum as it is Oracle.
SELECT t.employee_id, t.salary
FROM
(
SELECT distinct employee_id, salary, rownum as row from
FROM yourTable order by salary desc
) t
WHERE t.row = 2;

Oracle SQL - order table

I am new to Oracle SQL and have a table below.
TABLE NAME : ORDERS
CNUM AMT SNUM
1001 1000 2001
1002 2000 2002
1001 1500 2001
1001 500 2001
need to get only those data where cnum (customer number) is serviced by more than 3 snum(sales person) from this above table
thank you
Asit
Something like that?
select cnum, count(*), sum(amount)
from orders
group by cnum
having count(*) > 3
Not sure what you need - aggregate result or every single row. If you need every row then try this one:
select * from (
select a.*, count(*) over(partition by cnum) cnt
from orders a
)
where cnt > 3
You could use the analytic function ROW_NUMBER.
For example,
SQL> WITH DATA AS(
2 SELECT t.*, row_number() OVER(PARTITION BY cnum ORDER BY snum) rn FROM t
3 )
4 SELECT cnum, amt, snum FROM DATA
5 WHERE rn >=3;
CNUM AMT SNUM
---------- ---------- ----------
1001 1500 2001
SQL>
Based on your sample data, the above gives the result including 3 snum for cnum, if you want more than 3, then replace >= with >.
You can group and count distinct SNUMs:
select CNUM
from ORDERS
group by CNUM
having count(distinct SNUM) > 3
WITH tab
AS (SELECT 1001 CNUM, 1000 AMT, 2001 SNUM FROM DUAL
UNION ALL
SELECT 1002, 2000, 2002 FROM DUAL
UNION ALL
SELECT 1001, 1500, 2001 FROM DUAL
UNION ALL
SELECT 1001, 500, 2001 FROM DUAL)
SELECT cnum
FROM tab
GROUP BY cnum
HAVING COUNT (*) >= 3;
If you only need the cnum and the snum you could do the following witch is partially taken from Rusty's answer:
WITH tab
AS (SELECT 1001 CNUM, 1000 AMT, 2001 SNUM FROM DUAL
UNION ALL
SELECT 1002, 2000, 2002 FROM DUAL
UNION ALL
SELECT 1001, 1500, 2001 FROM DUAL
UNION ALL
SELECT 1001, 500, 2001 FROM DUAL)
SELECT DISTINCT cnum, snum
FROM (SELECT cnum, snum, COUNT (*) OVER (PARTITION BY cnum) RANK FROM tab)
WHERE RANK >= 3;