I have to create a column at run time (RANK of salary ) ,which depends on the value of a salary column from one table(COLLAGE ) and this salary is associated with an employee table. Can you suggest how to generate it . The RANK column will contain the value based on salary i.e if the salary is highest than RANK is 1 ... in ascending order.
This would get you id of your employee, their salary and a rank column.
SELECT
*,
#currentRank := #currentRank + 1 AS rank_of_salary
FROM (
SELECT
c.employee_id,
e.salary
FROM
collage c
INNER JOIN employee e ON c.employee_id = e.employee_id
) t, (SELECT #currentRank := 0) r
ORDER BY salary
(SELECT #currentRank := 0) initializes a variable so that you do not need separate SET statement.
For each row #currentRank variable is being increased and stored in rank_of_salary column. It's actually more a row_number equivalent I believe. Proper ordering of this rank is maintained by sorting the output with ORDER BY salary clause.
Related
Let us say, I want to find the second highest salary. For that I use the following query.
select b.Salary as SecondHighestSalary from
(
select Salary, rank() over (order by Salary desc) as r
FROM Employee
) b
WHERE b.r = 2;
However, I want this to return null when the table only contains one entry, and therefore there is no 2nd highest salary. How can I do that?
Use your query with aggregation:
select max(Salary) as SecondHighestSalary
from (
select Salary, rank() over (order by Salary desc) as r
FROM Employee
) t
where r > 1;
The aggregate function max() will return null in case there is no 2nd highest salary.
One method would be:
select (select distinct salary
from employee
order by salary desc
limit 1 offset 1
);
The subquery returns NULL if the select distinct only returns one row.
With your structure, you can use conditional aggregation:
select max(case when seqnum = 2 then e.Salary end) as SecondHighestSalary
from (select Salary,
rank() over (order by Salary desc) as seqnum
from Employee e
) e;
Another easy hack with combination of union and limit.Below query will return null for no rows as well as single row.For more than one row it returns second largest salary.
select * from
(
select b.Salary as SecondHighestSalary from
(
select Salary, rank() over (order by Salary desc) as r
FROM Employee
) b
WHERE b.r = 2
union
select null) tab limit 1;
Refer DB Huddle link for full solution -https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=8b8b537160ca61e29da39a4662151217
Limit it to 1 result with rank of 1 or 2 and see if the rank is 2?
select if(c.r=2,c.Salary,NULL) SecondHighestSalary
from (
select b.Salary, b.r
from (
select Salary, rank() over (order by Salary desc) as r
FROM Employee
) b
where b.r <= 2
order by b.r
limit 1
) c
Even that will not return any results if there are no entries in Employee. If you want NULL in that case too, do:
select c.SecondHighestSalary
from (select 1) dummy
left join (
select b.Salary as SecondHighestSalary from
(
select Salary, rank() over (order by Salary desc) as r
FROM Employee
) b
WHERE b.r = 2
) c;
You can use the following:
WITH cteDesired_rank(desired_rank)
AS (SELECT 2)
select DISTINCT b.Salary as SecondHighestSalary
from cteDesired_rank rr
LEFT OUTER JOIN (select Salary, rank() over (order by Salary desc) as r
FROM employee) b
ON b.r = rr.desired_rank
WHERE rr.desired_rank = 2
Here we use a common table expression to specify the rank number that we want. We select first from the common table expression because we know that our desired rank number will be present. We then outer join to the rank subquery from employee where the desired rank number might be present, but is not required to be. We then filter for desired_rank = 2 - the desired_rank value will always be present, but the calculated rank value may not be. As such, if the subquery returns rows with the desired rank they will be displayed, but if the subquery does not return rows with the desired rank value the desired rank from the common table expression will still be returned, but the salary value will be NULL.
db<>fiddle here
Suppose we have one table called emp that has only one column called salary that has 6 rows only.
I want the result that add the (difference of second highest and third highest salary) and (difference of fourth highest and fifth highest salary).
Note: I don't want to use any inner query for that. so please help me to write this query ?
Thanks in advance
Please find table below : (this table is not in sorted order)
|Salary|
--------
|150000|
|130000|
|140000|
|160000|
|180000|
|190000|
I have wrote this following query that given the data but as data is not in sorted order so i am facing the issue
ABS(ABS((select salary
from EMP where rownum <3 minus select salary from EMP
where rownum <2 )-
(select salary
from EMP where rownum <2 minus select salary from EMP
where rownum <1))-
ABS((select salary
from EMP where rownum <5 minus select salary from EMP
where rownum <4 )-
(select salary
from EMP where rownum <4 minus select salary from EMP
where rownum <3 )))
For Oracle:
Hard to do without subqueries... unless you are looking for really ugly and inefficient code.
Here is a neat way to do it without subqueries, in Oracle 12.1 and higher, using the match_recognize clause:
with
emp ( salary ) as (
select 150000 from dual union all
select 130000 from dual union all
select 140000 from dual union all
select 160000 from dual union all
select 180000 from dual union all
select 190000 from dual
)
-- End of simulated inputs (for testing only, not part of the solution!)
-- SQL query begins BELOW THIS LINE.
select result
from emp
match_recognize (
order by salary desc
measures (b.salary - c.salary) + (d.salary - e.salary) as result
one row per match
pattern ( ^ a b c d e )
define a as 0 = 0
)
;
RESULT
------
30000
And here is an elementary (and stupid!) way to do it:
select max(e2.salary) - max(e3.salary) + max(e4.salary) - max(e5.salary) as result
from emp e1 join emp e2 on e1.salary > e2.salary
join emp e3 on e2.salary > e3.salary
join emp e4 on e3.salary > e4.salary
join emp e5 on e4.salary > e5.salary
;
You may use NTH_VALUE Oracle function.
SELECT distinct ((NTH_VALUE(salary, 2) OVER (ORDER BY salary DESC RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)) -
(NTH_VALUE(salary, 3) OVER (ORDER BY salary DESC RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING))) +
((NTH_VALUE(salary, 4) OVER (ORDER BY salary DESC RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)) -
(NTH_VALUE(salary, 5) OVER (ORDER BY salary DESC RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)))
FROM emp
I want to get the "rank" of a specific Name in my database.
So if I type in Julia, I want to get #2. (Her rank/place in the database)
Name Points
Julia 1987
Marc 1479
Sophia 2517
select rank
from
(
select name, #rank := #rank + 1 as rank
from your_table
cross join (select #rank := 0) r
order by points desc
) tmp
where name = 'Julia'
The inner select orders the data and adds a rank column. The outer select gets the rank of the specific person.
Here is my query:
SET #rank=0;
SELECT #rank := #rank +1 AS rank_id, name, SUM(points) AS points
FROM battle_points
WHERE category = 'test'
AND user_id !=0
GROUP BY user_id
ORDER BY points DESC;
I'd like to add a column rank based on the total points. With this query, the points are fine but the rank_id virtual column doesn't match up.
For example, the top user with the most points has rank 26, yet the rank_id column has a value of 24.
How do I matchup the rank_id column with the points column?
Note: while I am fully versed in PHP, I need a solution for MySQL only.
You are on the right path, but you need to put the main query in a subquery so that the ordering occurs before the rank calculation, like so:
SET #rank=0;
SELECT #rank := #rank +1 AS rank_id, mainQ.*
FROM (
SELECT name, SUM(points) AS points
FROM battle_points
WHERE category = 'test'
AND user_id !=0
GROUP BY user_id
ORDER BY points DESC
) AS mainQ
;
Edit: Qualified * to mainQ.*.
How to get ONLY the name of second (or nth) highest salaried person?
This is the query I have tried but this gives me only the name of highest salary paid:
SELECT emp_name FROM emp ORDER BY salary DESC LIMIT 1;
Not sure if that the best solution, but here is an example how you could do it:
SELECT * FROM (
SELECT customerName, length(customerName), #rownum := #rownum + 1 AS rank
FROM zenyatech.customer, (SELECT #rownum := 0) r
ORDER BY length(customerName)
) X WHERE rank = 2
You create a rank column first, and then use a query around that query and get only rank = 2 or N.
(The example is a little different, you would need to apply that to your table/database scenario)
This might help
SELECT name FROM employees ORDER BY salary DESC LIMIT 1,1