How to retreive 5 highest values from a table - mysql

I have table with 10 rows with employee id and salary.
I want get a table with 5 rows in order of the highest salary.
create table employee(
id int not null primary key,
employeeName VarChar(20),
salary int
);
Thank you.

You can use RANK(), or DENSE_RANK, or ROW_NUMBER().
For example:
select *
from (
select *,
rank() over(order by salary desc) as rk
from employee
) x
where rk <= 5
order by rk, employeename
See running example (that show 6 rows since two are tied in fifth place) at DBFidle.

Related

In SQL, How to output "NULL" instead of " There are no results to be displayed" when there's no value to be exported

Using MySQL v8.0 right now.
The question is:
Write an SQL query to report the id and the salary of the second highest salary from the
Employee table. If there is no second highest salary, the query should
report null.
My dummy data is:
Create table If Not Exists Employee (id int, salary int);
insert into Employee (id, salary) values
(1, 100);
My ideal output is like this:
+------+--------+
| id | salary |
+------+--------+
| NULL | NULL |
+------+--------+
I used DENSE_RANK as a more straightforward way for me to solve this question:
WITH sub AS (SELECT id,
salary,
DENSE_RANK() OVER (ORDER BY salary DESC) AS num
FROM Employee )
SELECT id, salary
FROM sub
WHERE num = 2
But I have a problem exporting NULL when there's no second highest salary. I tried IFNULL, but it didn't work. I guess it's because the output is not actually null but just empty.
Thank you in advance.
WITH sub AS (
SELECT id,
salary,
DENSE_RANK() OVER (ORDER BY salary DESC) AS num
FROM Employee
)
SELECT id, salary
FROM sub
WHERE num = 2
UNION ALL
SELECT NULL, NULL
WHERE 0 = ( SELECT COUNT(*)
FROM sub
WHERE num = 2 );
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=31f5afb0e7e5dce9c2c128ccc49a6f42
Just making your query a subquery and left joining from a single-row producing subquery seems to me the simplest approach:
select id, salary
from (select null) at_least_one_row
left join (
select id, salary
from (
select id, salary, dense_rank() over (order by salary desc) as num
from Employee
) ranked_employees
where num = 2
) second_highest_salary on true
(I usually prefer a subquery to a cte that's only used once; I find that obfuscatory.)

select the rows that have more that X occurrences of the same foreign key and ignore the X most recent (timestamp)

I have a table with a property that is a foreign key and another property that is a timestamp
Table
id
fk
timestamp
1
2
16-02-2022
2
2
01-02-2022
3
2
02-02-2021
4
3
24-05-2020
5
3
11-01-2022
6
3
16-09-2021
7
3
01-01-2022
I want to select the rows that have more that X ocurrences of the same foreign key and i want to ignore the X most recent(timestamp) elements for each foreign key
So basically with a X of 2 the select would return
id
fk
timestamp
3
2
02-02-2021
6
3
16-09-2021
4
3
24-05-2020
And with a X of 3 the select would return
id
fk
timestamp
4
3
24-05-2020
Edit:
Thanks alot #forpas for the awesome aproach
Solution
SELECT id, fk, timestamp
FROM (
SELECT *,
COUNT(*) OVER (PARTITION BY fk) counter,
ROW_NUMBER() OVER (PARTITION BY fk ORDER BY timestamp DESC) rn
FROM tablename
) t
WHERE counter > ? AND rn > ?;
Use COUNT() and ROW_NUMBER() window functions:
SELECT id, fk, timestamp
FROM (
SELECT *,
COUNT(*) OVER (PARTITION BY fk) counter,
ROW_NUMBER() OVER (PARTITION BY fk ORDER BY timestamp DESC) rn
FROM tablename
) t
WHERE counter > ? AND rn > ?;
Replace ? with the values that you want.
But, if the same number X is applied for both the number of total rows for each fk and the number of rows to be dismissed, the query can be simplified:
SELECT id, fk, timestamp
FROM (
SELECT *, ROW_NUMBER() OVER (PARTITION BY fk ORDER BY timestamp DESC) rn
FROM tablename
) t
WHERE rn > ?;
See the demo.
SELECT
id, fk, timestamp
FROM
(
SELECT id, fk, timestamp, ROW_NUMBER() OVER(PARTITION BY fk ORDER BY timestamp ASC) AS X,
COUNT(1) OVER(PARTITION BY fk) AS Total
FROM MyTable
) AS S
WHERE A.Total - S.X >= #X

Querying with a last occurrence similar to the current record

I have this scenario
I need to return the last and second to last records with the same type_id searching all records in the table
Example:
Article ID | Last Article ID that uses the same type_id on your details of the Article ID from the first column
With this data above would be the following return:
Article ID - Last Article ID with the same type_id
4 - 2
3 - null
How can be the query to return this result?
Thanks
In MySQL 8.0, you can use lag() and row_number():
select
article_id,
last_article_id
from (
select
article_id,
lag(article_id) over(partition by type_id order by details_id) last_article_id,
row_number() over(partition by type_id order by details_id desc) rn
from mytable
) t
where rn = 1
If you are using a 5.x Version of mysql
You can try
SELECT
IF(rnk = 1,Article_ID,0) article_id
,MAX(IF(rnk = 2,Article_ID,NULL)) last_article_id
FROM
(SELECt
t1.Article_ID
,if(#id <> Type_id, #rnk:=0,#rnk:= #rnk)
,#rnk := #rnk +1 rnk
,#id := Type_id Type_ID
FROM
(SELECT * FROM article_Detail ORDER By Type_ID,Article_ID DESC) t1,(SELECT #rnk := 1) r1,
(SELECT #id := 0) i
) articcledetail
GROUP BY Type_ID;
Table
CREATE TABLE article_Detail (
DETAIL_ID INT,
Article_ID INT,
Type_ID INT);
INSERT INTO article_Detail values (100,1,1),(101,2,1),(102,3,2),(103,4,1);
I am ordering your Articlwe details table by their type_id and then article ID to get the highest article id as first entry to rank it.

Comparing values within a column using sql

I have a table with three columns Member, id and DOB. I want to assign a id to each unique member. If there is more than one id tagged for a member then I have to assign id with more recurrence. If a tie occurs then I have to assign id with most recent DOB.
4000 8569 11/11/1993
4111 9653 12/11/1993
4000 8569 12/12/1993
5000 5632 01/01/1993
4000 6932 31/12/1993
4111 6987 06/11/1993
5001 4356 01/01/1993
In the above, member's 5000 and 5001 is tagged to single id.. So I should get the same id for that member.. Whereas for member 4000 I am having 3 id's- 2 same ids (8569) and one different id (6987). Here I should have 8569 tagged to this 4000 member. For 4111 member, I am having two different ids (9653 and 6987). So I will see recent DOB for that member. So for 4111 member I will have 9653 tagged to it.
The output should be like this:
4000 8569
4111 9653
5000 5632
5001 4356
I have tried many. But I couldn't get the exact answer. Please help me to solve this. Thanks in advance.
You can do this with window functions in t-sql:
create table #t (
Member int,
id int,
DOB date
);
insert into #t
values (4000, 8569, '1993-11-11'),
(4111, 9653, '1993-11-12'),
(4000, 8569, '1993-12-12'),
(5000, 5632, '1993-01-01'),
(4000, 6932, '1993-12-31'),
(4111, 6987, '1993-11-06'),
(5001, 4356, '1993-01-01');
with cte as
(
select *, count(id) over (partition by member, id) cnt from #t
),
cte2 as
(
select *, row_number() over (partition by member order by cnt desc, dob desc) rn from cte
)
select member, id from cte2 where rn = 1;
drop table #t;

Mysql retriving the nth record

Suppose I have a table named EMPLOYEE containing the following attributes
(EMPLOYEE_ID, LAST_NAME, FIRST_NAME, MIDDLE_NAME, JOB_ID, MANAGER_ID, Salary)
Can I
Display the Nth highest salary drawing employee details
Please help
ORDER BY and LIMIT where 10 is n + 1:
SELECT
*
FROM
employees
ORDER BY
Salary DESC
LIMIT
10, 1
(If you want the first record, use LIMIT 0, 1. For the tenth, use LIMIT 9, 1 etc.)
try this
put n > 1 to get corresponding results
n=3 must give you second highest salary
SELECT * --This is the outer query part
FROM Employee Emp1
WHERE (N-1) = ( /* Subquery starts here */
SELECT COUNT(DISTINCT(Emp2.Salary))
FROM Employee Emp2
WHERE Emp2.Salary > Emp1.Salary)
Test Table
CREATE TABLE Test
(ID INT IDENTITY(1,1),
Salary INT)
INSERT INTO Test
VALUES (100), (200), (300), (400), (500)
SELECT * FROM Test
Query
SELECT TOP 1 Salary
FROM
(SELECT TOP 3 Salary FROM Test ORDER BY Salary DESC)q
ORDER BY Salary ASC
In your Sub-query SELECT TOP Nth the rest remains the same and it will get you the desired results