Oracle, row_number, deleting rows - sql

I have a little problem. Here's a code:
select * from
(select department_id, manager_id,last_name, salary, row_number() over
(partition by department_id,manager_id order by salary asc) p_number
from employees )
where p_number <=3;
This query shows 3 the least salaries in every department for every manager in department
ex: Dep no.30 has 2 managers (100 and 114), manager no.100 has 1 employee beneath him, manager no.114 - 3 employees.
part of result:
20 100 Hartstein 13000 1
20 201 Fay 6000 1
30 100 Raphaely 11000 1
30 114 Colmenares 2500 1
30 114 Himuro 2600 2
30 114 Tobias 2800 3
Now, i want to delete all rows, where there is only 1 employee beneath manager. In this example there should be, Harstein, Fay, Raphaely. Colmenares also has number 1, but there is more employees under manager 114.
Any ideas?
PS Having Count is out, because there is no group by, and modifying
where p_number <=3;
into
where p_number <=3 and p_number >1;
is also out, because it will delete all my employees with no.1 and i want to 'safe' few as they have more 'colleagues' :)
Thanks!

This will give the result and only require a single table scan:
SELECT *
FROM (
SELECT department_id,
manager_id,
last_name,
salary,
ROW_NUMBER()
OVER ( PARTITION BY department_id, manager_id
ORDER BY salary ASC ) AS p_number,
COUNT(*)
OVER ( PARTITION BY department_id, manager_id ) AS p_count
FROM employees
ORDER BY department_id, manager_id, salary
)
WHERE p_count >= 2
AND p_number <= 3;
Output:
DEPARTMENT_ID MANAGER_ID LAST_NAME SALARY P_NUMBER P_COUNT
------------- ---------- ---------- ---------- ---------- ----------
30 114 Colmenares 2500 1 3
30 114 Himuro 2600 2 3
30 114 Tobias 2800 3 3

Related

Trying to find an Oracle query to find nth highest salary and among them one with highest experience

I need to find name of the person with 3rd highest salary
The table in question is as follows:
Name Salary Experience
-------------------------------
Den 11000 114
Gerald 11000 148
Ellen 11000 174
Eleni 10500 149
Clara 10500 162
Janette 10000 156
Peter 10000 150
Hermann 10000 204
Harrison 10000 169
I need to find name of the person having max experience and in the 3rd highest salary bracket.
So evidently, 3rd highest salary is 10000 and max experience among those having 3rd highest salary is Hermann with exp of 204.
I have query to find the 3rd highest salary:
select name, salary, experience
from sal s1
where 3 - 1 = (select count(distinct salary)
from sal s2
where s2.salary > s1.salary);
But this query returns 4 rows and I need to know how I can filter it even further in this same query to find Hermann with exp of 204.
Use the DENSE_RANK analytic function to find the 3rd highest salary and the ROW_NUMBER (or RANK or DENSE_RANK) analytic function with a PARTITION BY clause to find the highest experience per salary. This only requires a single table/index scan.
Oracle Setup:
CREATE TABLE table_name ( Name, Salary, Experience ) AS
SELECT 'Den', 11000, 114 FROM DUAL UNION ALL
SELECT 'Gerald', 11000, 148 FROM DUAL UNION ALL
SELECT 'Ellen', 11000, 174 FROM DUAL UNION ALL
SELECT 'Eleni', 10500, 149 FROM DUAL UNION ALL
SELECT 'Clara', 10500, 162 FROM DUAL UNION ALL
SELECT 'Janette', 10000, 156 FROM DUAL UNION ALL
SELECT 'Peter', 10000, 150 FROM DUAL UNION ALL
SELECT 'Hermann', 10000, 204 FROM DUAL UNION ALL
SELECT 'Harrison', 10000, 169 FROM DUAL
Query: If you want to find "the person having max experience in the 3rd highest salary bracket":
SELECT Name, Salary, Experience
FROM (
SELECT t.*,
DENSE_RANK() OVER ( ORDER BY Salary DESC ) AS s_rank,
ROW_NUMBER() OVER ( PARTITION BY Salary ORDER BY Experience DESC )
AS Exp_rownum
FROM table_name t
)
WHERE s_rank = 3
AND Exp_rownum = 1;
If you swap the ROW_NUMBER() analytic function for either RANK() or DENSE_RANK() then this will return multiple people if they are tied with the joint highest experience in the 3rd highest salary bracket.
Output:
NAME | SALARY | EXPERIENCE
:------ | -----: | ---------:
Hermann | 10000 | 204
Query: If you want to find "the person having max experience and (also) in the 3rd highest salary bracket":
Just take the query above and remove the PARTITION BY clause.
SELECT Name, Salary, Experience
FROM (
SELECT t.*,
DENSE_RANK() OVER ( ORDER BY Salary DESC ) AS s_rank,
ROW_NUMBER() OVER ( ORDER BY Experience DESC ) AS Exp_rownum
FROM table_name t
)
WHERE s_rank = 3
AND Exp_rownum = 1;
Output:
(Note: if Herman's experience was 173 then this would not return any rows as Ellen would have the highest experience but she would not be in the 3rd highest salary bracket and Herman would be in the 3rd highest salary bracket but would only have the 2nd highest experience.)
NAME | SALARY | EXPERIENCE
:------ | -----: | ---------:
Hermann | 10000 | 204
db<>fiddle here
This query makes use of ROWNUM and MAX to find the right row. In the innermost sub-query the max experience is retreived for each salary level, ordered by salary descending, and then in the outer sub-query row numbers are added and this is joined with the original table to find the correct row(s)
SELECT s.name, s.salary, s.experience
FROM sal s
JOIN (SELECT s2.*, ROWNUM rnum
FROM (SELECT salary, max(experience) AS m_exp
FROM sal
GROUP BY salary
ORDER BY salary DESC) s2) s3 ON s3.salary = s.salary AND
s3.m_exp = s.experience AND
rnum = 3
You don't query on the experience. So you've to add a where-clause:
select name, salary, experience
from sal s1
where 3 - 1 = (select count(distinct salary)
from sal s2
where s2.salary > s1.salary)
and experience = (select max(experience) from sal)
UPDATE
The alternative (max experience within 3rd highest salary) should be:
select name, salary, experience
from sal s1
where 3 - 1 = (select count(distinct salary)
from sal s2
where s2.salary > s1.salary)
and experience = (select max(experience) from sal s3
where 3 - 1 = (select count(distinct salary)
from sal s4
where s4.salary > s3.salary)
)

Find the average value from the previous row and the current row for a same department id

I have 3 employees with the same departments. i wanted to find the average of their salaries based on the previous rows.
For example
Employee_id department_id salary avg(salary)
101 1 5000 5000
102 1 10000 7500
103 1 15000 10000
This is like for department id as 1 with first salary we find the average as 5000 for employee id 101 and for the same department id as 1 for the employee id as 102 , we find the average for the 2 values grouped by department id.
Hence
average is (10000+5000) /2 = 7500
But for the employee id as 103, department id is 1 and is grouped with all the above three values of amount.
Hence,
average of salary is (10000+5000+15000)/3 = 10000
The requirement is i have been asked to use query_partition_clause and order_by_clause.
Hence i tried as follows,
select avg(salary) OVER (partition by department_id ORDER BY department_id ) salary, department_id, salary from employee
But i am always getting the values by considering the department of 3 data values.
Henceforth can somebody help on this resolution?
Many Thanks for the help.
Use ORDER BY salary (or ORDER BY employee_id) rather than ORDER BY department_id:
Oracle Setup:
CREATE TABLE employees ( Employee_id, department_id, salary ) AS
SELECT 101, 1, 5000 FROM DUAL UNION ALL
SELECT 102, 1, 10000 FROM DUAL UNION ALL
SELECT 103, 1, 15000 FROM DUAL;
Query:
SELECT e.*,
AVG( salary ) OVER ( PARTITION BY department_id ORDER BY salary ) AS avg_salary
FROM employees e
Output:
EMPLOYEE_ID | DEPARTMENT_ID | SALARY | AVG_SALARY
----------: | ------------: | -----: | ---------:
101 | 1 | 5000 | 5000
102 | 1 | 10000 | 7500
103 | 1 | 15000 | 10000
db<>fiddle here
SELECT EMPLOYEE_ID,
DEPARTMENT_ID,
SALARY,
(SELECT AVG(SALARY)
FROM EMPLOYEES B
WHERE B.EMPLOYEE_ID <= A.EMPLOYEE_ID) AVG_SALARY
FROM EMPLOYEES A
GROUP BY EMPLOYEE_ID,
DEPARTMENT_ID,
SALARY
A sub query can be done in the query itself by filtering the employee ID. I hope I have helped with something.

Query to find least fifth salaried employee [duplicate]

This question already has answers here:
Select second most minimum value in Oracle
(3 answers)
Closed 4 years ago.
EMPID NAME DEPTID SALARY
---------- ------------------------------------------ --
101 surendra 201 1000
102 narendra 202 2000
103 rajesh 203 3000
104 ramesh 203 2000
105 hanumanth 202 10000
a) Write a Query to find least 5th (Least salary in 5th position from
least salary in the order) salaried employee?
b) Query to find the highest earning employee in each department
a) Write a Query to find least 5th (Least salary in 5th position from least salary in the order) salaried employee?
SELECT EMPID,NAME,DEPTID,SALARY
FROM
(
SELECT EMPID,NAME,DEPTID,SALARY, DENSE_RANK() OVER (ORDER BY SALARY) AS RN
FROM Table1
)
WHERE RN=5
b) Query to find the highest earning employee in each department
SELECT EMPID,NAME,DEPTID,SALARY
FROM
(
SELECT EMPID,NAME,DEPTID,SALARY,
DENSE_RANK() OVER (PARTITION BY DEPTID ORDER BY SALARY DESC) AS RN
FROM Table1
)
WHERE RN=1
Demo
http://sqlfiddle.com/#!4/63ce0/12
Let's assume we have a table named EmployeeSalary which has 3 columns:
Id
Name
Salary
Salary might be same for multiple employee according to the following table data
Id Name Salary
----------
6 Belalo 74
1 Karim 100
5 dIPU 100
4 Satter 102
9 Kiron 120
10 Rash 120
11 Harun 130
13 Baki 130
12 Munshi 132
2 Rahim 500
7 Kaif 987
8 Sony 987
3 Belal 4000
Now the query will be
SELECT A.Salary
FROM
(
SELECT DISTINCT Salary,
DENSE_RANK() OVER (ORDER BY Salary) AS Ranks
FROM [dbo].[EmployeeSalary]
) A
WHERE A.Ranks=5

How to retrieve max salary of employee from each department

Consider the table Employee:
Department number Employee_id Salary
1 123 2000
1 234 3266
1 657 3265
2 546 2050
2 657 3000
2 121 6000
3 131 6500
3 141 5000
3 151 1050
Now I want to retrieve the employee_id having highest salary from each department. How to write the query for this?
A good way to approach these queries is using row_number():
select department_number, employee_id, salary
from (select e.*, row_number() over (partition by department order by salary desc) as seqnum
from employee e
) e
where seqnum = 1;
If you want to get multiple rows for a department when there are ties, then use dense_rank() or rank() instead of row_number().
Try this
SELECT Dept_Num,EmpID,Salary
from Employee
WHERE Salary IN (Select MAX(Salary) from Employee Group By Dept_Num)
Can you use the max statement:
Select departament_number,employee_id,salary
from employee
where salary in (select MAX(salary) from employee group by departament_number)

getting error as too many values in my query

dpt_no salary period start_date end_date
------ ----- ------ ---------- --------
100 12580 15months 12-DEC-07 10-DEC-10
101 15500 19months 10-JAN-07 10-DEC-11
102 7777 18months 11-JUL-07 21-APR-11
103 9999 11months 07-JUL-07 31-JAN-11
104 8500 9months 12-MAR-07 27-MAR-11
105 10000 20months 17-SEP-07 01-AUG-11
106 25000 7months 17-NOV-07 26-JUL-11
107 100000 6months 05-MAY-07 21-JUN-11
108 35000 16months 28-FEB-08 21-JUN-11
109 5000 16months 02-DEC-08 19-AUG-11
i'm write query for giving rank to salary and getting that rank using ampersand. That query is
select salary from salary
where &RANK=(select salary, rank() over(order by salary desc)
as "rank" from salary salary).
BUT i'm getting error as "too many values". can any one help me please
It should be something like this:
select t1.salary from
(select salary.salary,
rank() over(order by salary desc)
as "rank" from salary) t1
where "rank"=&RANK
SQLFiddle demo