Split the results of a query into parts
Question
I got this question in an exam, the teacher asked us to raise the employers' salaries using the following rules using a cursor:
- An extra 4% for the first quarter with the highest salary.
- An extra 6% for the second quarter with the highest salary.
- For the rest an extra 8%
How to approach solving this.
My attempt was SELECT SALARY FROM (SELECT * FROM EMP ORDER BY SALARY) rownum > count(*)/4
to get the salary at first then add the %4 raise and update it to the new value.
I haven't tested it but I guess it might work, but I think it's a bit too far fetched and there may be a better or more efficient solution, your thought guys ?
Solution
To solve your issue, I did the following:
Create table and data:
CREATE TABLE salesperson (id INTEGER, salary INTEGER);
INSERT INTO salesperson VALUES (1, 100000);
INSERT INTO salesperson VALUES (2, 80000);
INSERT INTO salesperson VALUES (3, 60000);
INSERT INTO salesperson VALUES (4, 50000);
INSERT INTO salesperson VALUES (5, 30000);
INSERT INTO salesperson VALUES (6, 25000);
INSERT INTO salesperson VALUES (7, 12000);
INSERT INTO salesperson VALUES (8, 10000);
Then run this query (SQLFiddle here):
WITH cte AS
(
SELECT id, salary, NTILE(4) OVER (ORDER BY salary) AS quartile
FROM salesperson
) -- <<== you can do a SELECT * FROM cte to see what's happening!
SELECT
id,
salary,
CASE quartile
WHEN 1 THEN salary * 1.08
WHEN 2 THEN salary * 1.08
WHEN 3 THEN salary * 1.06
WHEN 4 THEN salary * 1.04
END as new_salary
FROM cte;
Result:
ID SALARY NEW_SALARY
1 100000 104000
2 80000 83200
3 60000 63600
4 50000 53000
5 30000 32400
6 25000 27000
7 12000 12960
8 10000 10800
HTH and welcome to the forum! :-)
You can read the Oracle NTILE documentation here and an explanation from the excellent oracle-base site here.
EDIT:
You can also do it in one pass - but I think the cte (COMMON TABLE EXPRESSION - or WITH clause) shows the thought process more clearly. Thus:
SELECT
id,
salary,
CASE NTILE(4) OVER (ORDER BY salary)
WHEN 1 THEN salary * 1.08
WHEN 2 THEN salary * 1.08
WHEN 3 THEN salary * 1.06
WHEN 4 THEN salary * 1.04
END as new_salary
FROM salesperson
ORDER BY id;
Same result (fiddle)!
OTHER TIPS
I meant the idea, not the literal implementation of the query
I'll write the idea too, well?
WITH cte AS ( SELECT *, RANK(salary) OVER (PARTITION BY quarter ORDER BY salary DESC) rnk
FROM datatable )
UPDATE datatable
SET salary = salary * CASE WHEN rnk=1 AND quarter=1 THEN 1.04
WHEN rnk=1 AND quarter=2 THEN 1.06
ELSE 1.08 END
FROM cte
WHERE id = cte.id