how to fetch top distinct data in sqlserver - sql

I have a table named employee_salary, with three columns: empsal_id, empsal_name and empsal_sal. The data is as follows:
empsal_id empsal_name empsal_sal
1 dilip 14000
2 santosh 20000
3 amit 32000
4 dilip 22000
5 amit 38000
6 santosh 25000
7 dilip 30000
The empsal_id is an Identity column with a Seed and an Increment of 1, and is the Primary Key. I want to return the name and current salary of each employee. Salary can decrease as well as increase, so current does not necessarily mean highest.
So I need the following output:
empname emp_sal
dilip 30000
amit 38000
santosh 25000
I am using Microsoft SQL Server, and I have to do this in a single query.

This query will return each employee, along with their highest salary:
SELECT
empsal_name, MAX(empsal_sal)
FROM
employee
GROUP BY
empsal_name
This query will return each employee, along with their current salary (i.e. the salary with the highest empsal_id:
SELECT
empsal_name, empsal_sal
FROM
employee e1
WHERE
empsal_id =
(SELECT MAX(empsal_id)
FROM employee e2
WHERE e1.empsal_name=e2.empsal_name)
Personally, I think you would be better off using an effective date column (e.g. empsal_effectivedate) to determine which record is the most current, so this query will return each employee, along with their current salary (i.e. the salary with the most recent empsal_effectivedate), assuming there is an empsal_effectivedate field:
SELECT
empsal_name, empsal_sal
FROM
employee e1
WHERE
empsal_effectivedate =
(SELECT MAX(empsal_effectivedate)
FROM employee e2
WHERE e1.empsal_name=e2.empsal_name)

Assuming there is also an ID in the table and also assuming that the larger this ID is the most recent the salary is for that employee you can do
SELECT DISTINCT
e.empname,
(SELECT TOP 1
emp_sal
FROM
employee s
WHERE
s.empname = e.empname
ORDER BY
recid DESC) AS emp_sal
FROM
employee e
(also assuming that empname is unique for an employee)
because of the many assumptions though : you should probably post all the columns of the table and what they mean ..

SELECT empname, MAX(emp_sal)
FROM employee
GROUP BY empname
UPDATED:
SELECT DISTINCT EmpA.empname,
EmpA.emp_sal
FROM Employee AS EmpA
INNER JOIN ( SELECT EmpName, MAX(recID) AS recid
FROM Employee
GROUP BY EmpName
) AS EmpB ON EmpA.recid = EmpB.recid;

You need a date field to determine the latest inserted row . In case if the table is linked to some other table which has date column in it .Then its pretty easy to fetch the current data .
For Example
Employee Table
{
EmpName varchar(30) PK,
EmpAddress varchar(255) ,
Company varchar(30),
CurrentTimeStamp Datetime
}
Salary Table
{
EmpName varchar(30) FK,
EmpSalary int
}
To get the Latest record use the CTE function
With LatestSal(EmpName ,EmpSalary)
AS
(
Select row_number() over (PARTITION BY b.[EmpName], order by CurrentTimestamp DESC) as seq
b.EmpName,b.EmpSalary
From Employee as a,
Salary as b
on a.[EmpName]=b.[EmpName]
)
Select EmpName,EmpSalary
from LatestSal
where seq=1

Related

Selecting the record(s) with the "second" highest something

I have written the following SQL commands for retrieving data from a table called Employee.
I was able to get the highest/maximum salary as well as the second highest/maximum salary, but I am having difficulty writing the same when the whole record needs to be returned.
Select all the employees.
SELECT * FROM Employee
Return the highest salary. This returns the maximum salary amount which is 90000
SELECT MAX(salary) FROM Employee
Return the employee record with the highest salary. This returns all the records of the person/people with their salary being the maximum salary which is 90000 that is only John Henry in this case.
SELECT *
FROM Employee
WHERE salary = ( SELECT MAX(salary) FROM Employee )
Return every other employee record; i.e. everyone except the one with the highest salary.
SELECT *
FROM Employee
WHERE salary != ( SELECT MAX(salary) FROM Employee )
Return the second highest salary. This returns the second maximum salary amount which is 85000
SELECT MAX(salary) FROM Employee
WHERE salary != ( SELECT MAX(salary) FROM Employee )
Return the employee record with the second highest salary. This returns all the records of the person/people with their salary being the second maximum salary which is 85000 that is only Michael Greenback in this case.
I am stuck in this... I tried using HAVING as an extra condition, but however I arrange it to specify a condition, I get syntax errors. How do I do this?
Window functions are the built-in functionality to do this. In particular, dense_rank():
select e.*
from (select e.*, dense_rank() over (order by salary desc) as seqnum
from employee e
) e
where seqnum = 2;
This is a SQL Server solution but can be easily re-written using limit N instead of top N. If your database doesn't support window functions, you could try this. If it does, Gordon's solution is the way to go.
with cte as
(select max(salary) as second_max
from employee
where salary in (select distinct top 2 salary -- top n is what makes this scalable
from employee
order by salary asc)) -- get top 2 salaries and sort them
select *
from employee
where salary = (select second_max from cte);

Highest salary per department (also same salary)

How can I select the highest salary on each department with a same salary.
My query is only to get the first row in each department with the same salary. But I want to select all max same salary on each department. Please help me out of this problem.
Below is the sample table:
PSD Department
----------------------
Yumang's Salary: $500
Paus Salary: $500
QA Department
----------------------
Villanueva: $1000
Calacar: $1000
Here's the code I am trying:
SELECT MAX(inter_department_votes.number_votes)
FROM employee_salary
GROUP BY dept_id
try selecting dept_id as well:
SELECT dept_id,
MAX(inter_department_votes.number_votes)
FROM employee_salary GROUP BY dept_id
Using RANK() function:
RANK provides the same numeric value for ties (for example 1, 1, 2, 4, 5).
SELECT *
FROM (
SELECT dept_id,
PersonName,
Salary,
RANK() OVER(PARTITION dept_id ORDER BY Salary DESC) AS SortBySalary
FROM employee_salary
)
WHERE SortBySalary = 1
Also, see this answer using MAX() function.
your table isn't clear to me. i can't understand why you're creating separate tables for all departments.
assuming you make two different tables, one for employees and one for department. this will make queries simpler for future and efficient database. In that case:
+----------+------------+------+-----+
|EmployeeID|EmployeeName|Salary|DepNo|
+----------+------------+------+-----+
| |
+----------+------------+------+-----+
+-----+-------+
|DepNo|DepName|
+-----+-------+
| |
+-----+-------+
SELECT DepName, EmployeeName, salary
FROM Department d
INNER JOIN Employee e on e.DepNo = d.DepNo
INNER JOIN
(
SELECT DepNo, MAX(salary) sal
FROM Employee
GROUP BY DepNo
) ss ON e.DepNo = ss.DepNo
AND e.salary = ss.sal;

Second Highest Salary

Write a SQL query to get the second highest salary from the Employee table.
| Id | Salary |
| 1 | 100 |
| 2 | 200 |
| 3 | 300 |
For example, given the above Employee table, the query should return 200 as the second highest salary. If there is no second highest salary, then the query should return null.
| SecondHighestSalary |
| 200 |
This is a question from Leetcode, for which I entered the following code:
SELECT CASE WHEN Salary = ''
THEN NULL
ELSE Salary
END AS SecondHighestSalary
FROM (SELECT TOP 2 Salary
,ROW_NUMBER() OVER (ORDER BY Salary DESC) AS Num
FROM Employee
ORDER BY Salary DESC) AS T
WHERE T.Num = 2
It says that the query does not return NULL if there's no value for second highest salary.
For eg. if the table is
| Id | Salary|
| 1 | 100 |
The query should return
|SecondHighestSalary|
| null |
and not
|SecondHighestSalary|
| |
Solution to the Leetcode 2nd highest salary problem is:
Select
Max(Salary) AS SecondHighestSalary
from Employee
where Salary < (
Select Max(Salary) from Employee
);
In case of ties you want the second highest distinct value. E.g. for values 100, 200, 300, 300, you want 200.
So get the highest value (MAX(salary) => 300) and then get the highest value less than that:
select max(salary) from mytable where salary < (select max(salary) from mytable);
Using window functions, utilizing NTH_VALUE gives a clean answer
SELECT (
SELECT NTH_VALUE(Salary, 2) OVER(ORDER BY Salary DESC) AS SecondHighestSalary
FROM Employee
GROUP BY Salary
LIMIT 1 OFFSET 1 ) AS SecondHighestSalary
;
Detailed Break-Down:
The outer SELECT Statement is required to get NULL value incase a value was not found (second rank is not present for example, or table only has one row)
NTH_VALUE(Salary, 2) is basically saying, look at each group (in our case it divides the table based on groups of Salary) and for each group add a column that lists the second highest value, for every row within the same group from that new column, we want to pick the second most paid (so only second row)
NTH_VALUE() OVER(ORDER BY) is in ASC order by default, make sure you explicit the DESC order
NTH_VALUE() merely gives the order to the rows within each group (here Salary) incase of two similar salaries in the same salary group it will give them separate ranks (ex 1 and 2) even if they have same value in the same group, For this use GROUP BY () statement
Because NTH_VALUE() merely gives the order to the columns, based on a group USE LIMIT 1 to get just one value (top value) and OFFSET 1 (to make that top value our targeted second most paid)
you should be able to do that with OFFSET 1/FETCH 1:
https://technet.microsoft.com/en-us/library/gg699618(v=sql.110).aspx
SELECT id, MAX(salary) AS salary
FROM employee
WHERE salary IN
(SELECT salary FROM employee MINUS SELECT MAX(salary)
FROM employee);
You can try above code to find 2nd maximum salary.
The above code uses MINUS operator.
For further reference use the below links
https://www.techonthenet.com/sql/minus.php
https://www.geeksforgeeks.org/sql-query-to-find-second-largest-salary/
You can use RANK() function to rank the values for Salary column, along with a CASE statement for returning NULL.
SELECT
CASE WHEN MAX(SalaryRank) = 1 THEN NULL ELSE Salary as SecondHighestSalary
FROM
(
SELECT *, RANK()OVER(ORDER BY Salary DESC) As SalaryRank
FROM Employee
) AS Tab
WHERE SalaryRank = 2
It would be better to use the DENSE_RANK() function so that ranks don't get skipped whenever there is a tie for a position.
I would use DENSE_RANK() & do LEFT JOIN with employee table :
SELECT t.Seq, e.*
FROM ( VALUES (2)
) t (Seq) LEFT JOIN
(SELECT e.*,
DENSE_RANK() OVER (ORDER BY Salary DESC) AS Num
FROM Employee e
) e
ON e.Num = t.Seq;
While you can use a CTE (from MSSQL 2005 or newer) or ROWNUMBER the easiest and more "portable" way is to just order by twice using a subquery.
select top 1 x.* from
(select top 2 t1.* from dbo.Employee t1 order by t1.Salary) as x
order by x.Salary desc
The requisite to show null when there's not a second bigger salary is a bit more tricky but also easy to do with a if.
if (select count(*) from dbo.Employee) > 1
begin
select top 1 x.* from
(select top 2 emp.* from dbo.Employee emp order by emp.Salary) as x
order by x.Salary desc
end
else begin
select null as Id, null as Salary
end
Obs:. OP don't said what to do when the second largest is a tie with the first but using this solution is a simple matter of using a DISTINCT in the IF subquery.
Here is the easy way to do this
SELECT MAX(Salary) FROM table WHERE Salary NOT IN (SELECT MAX(Salary) FROM table);
You can try this for getting n-th highest salary, where n = 1,2,3....(int)
SELECT TOP 1 salary FROM (
SELECT TOP n salary
FROM employees
ORDER BY salary DESC) AS emp
ORDER BY salary ASC
Hope this will help you. Below is one of the implementation.
create table #salary (salary int)
insert into #salary values (100), (200), (300)
SELECT TOP 1 salary FROM (
SELECT TOP 2 salary
FROM #salary
ORDER BY salary DESC) AS emp
ORDER BY salary ASC
drop table #salary
The output is here 200 as 300 is first highest, 200 is second highest and 100 is the third highest as shown below
salary
200
Here n is 2
Query:
CREATE TABLE a
([Id] int, [Salary] int)
;
INSERT INTO a
([Id], [Salary])
VALUES
(1, 100),
(2, 200),
(3, 300)
;
GO
SELECT Salary as SecondHighestSalary
FROM a
ORDER BY Salary
OFFSET 1 ROWS FETCH NEXT 1 ROWS ONLY
| SecondHighestSalary |
| ------------------: |
| 200 |
select case
when cnt>1 then SecondHighestSalary
else null end as SecondHighestSalary
from
(select top 1 Salary as SecondHighestSalary,
(select count(distinct Salary) from Employee) as cnt
from (
select distinct top 2 Salary
from Employee
order by Salary desc ) as sal
order by SecondHighestSalary asc) as b
Select salary from employees limit 1,1 ;
Very easy way to find second highest salary
select
case when max(salary) is null then null else max(salary) end SecondHighestSalary
from (
select salary , dense_rank() over (order by salary desc) as rn
from Employee
)r
where rn = 2
This code returns null when there is no second highest salary
You can use the union condition to handle the null case
SELECT Salary as "SecondHighestSalary" from Employee
WHERE Salary < (SELECT MAX(salary) FROM Employee )
UNION
(SELECT null)
ORDER BY 1 DESC
LIMIT 1;
You can use exists() together with If-else statements.
Query:
If exists(select distinct salary as SecondHighestSalary from employee
order by salary desc offset 1 row fetch first 1 row only)
select distinct salary as SecondHighestSalary from employee
order by salary desc offset 1 row fetch first 1 row only
else select null as SecondHighestSalary;
#Please check the below code#
SELECT TOP 1 secondhighestsalary
FROM (SELECT
CASE WHEN z.SalaryRank >1 THEN Salary
ELSE null END secondhighestsalary, SalaryRank
FROM
(SELECT salary, RANK() OVER(ORDER BY Salary DESC) As SalaryRank
FROM Employee GROUP BY salary )z
GROUP BY Salary, SalaryRank
)c
ORDER BY secondhighestsalary DESC
Explanation:
** SELECT salary, RANK() OVER(ORDER BY Salary DESC) As SalaryRank
FROM Employee GROUP BY salary**
above query is to provide rank to Salary column, group by clause will take care the duplicate values ..... next
**SELECT
CASE WHEN z.SalaryRank >1 THEN Salary
ELSE null END secondhighestsalary, SalaryRank
FROM
(SELECT salary, RANK() OVER(ORDER BY Salary DESC) As SalaryRank
FROM Employee GROUP BY salary )z **
next piece of code assign NULL against rank 1 and salary for greater than 1 rank.
So if you have only one row in the table and as per our question we need to display second highest salary if not display NULL, it will take care that situation.
At last we need to Order by DESC and take the Top 1 record.
SELECT max(Salary) as SecondHighestSalary from Employee where salary <>(SELECT max(salary) from Employee)

I want to find any particular person name in my database

I've one database and I try to find the solution for my one query.
I want to find the 5th person name who earn a max salary in my database. so can I do
For example this is my execute query. you can see 7 people name but i want to see only 5th person name like only 'Mahesh"
my table is like that
FirstName varchar (45),
LastName varchar (45),
Birthdate datetime,
position varchar (35),
DOJ datetime,
DeptID int,
Salary decimal (10,2)
and this is my execute query. you can see 7 people name but i want to see only 5th person name like only 'Mahesh"
Salary Name
90000.00 Amita
90000.00 Carla
89500.00 Sarah
89000.00 Gunjan
85000.00 **Mahesh**
96000.00 John
86000.00 Charles
So my question is
I want to find the only one person name and salary from my data who earn 5th max salary.
Assuming you want the user with the 5th highest salary, you could use an embedded query.
SELECT TOP 1 *
FROM (SELECT TOP 5 *
FROM YourTable
ORDER BY Salary DESC) tmp
ORDER BY tmp.Salary
Or if you want to include ties.
SELECT *
FROM YourTable
WHERE Salary = (SELECT TOP 1 Salary
FROM (SELECT TOP 5 Salary
FROM YourTable
ORDER BY Salary DESC) tmp
ORDER BY tmp.Salary)

Find the second highest salary [duplicate]

This question already has answers here:
How to find the employee with the second highest salary?
(5 answers)
Closed 2 years ago.
Well it is a well known question. Consider the below
EmployeeID EmployeeName Department Salary
----------- --------------- --------------- ---------
1 T Cook Finance 40000.00
2 D Michael Finance 25000.00
3 A Smith Finance 25000.00
4 D Adams Finance 15000.00
5 M Williams IT 80000.00
6 D Jones IT 40000.00
7 J Miller IT 50000.00
8 L Lewis IT 50000.00
9 A Anderson Back-Office 25000.00
10 S Martin Back-Office 15000.00
11 J Garcia Back-Office 15000.00
12 T Clerk Back-Office 10000.00
We need to find out the second highest salary
With Cte As
(
Select
level
,Department
,Max(Salary)
From plc2_employees
Where level = 2
Connect By Prior (Salary) > Salary)
Group By level,Department
)
Select
Employeeid
,EmployeeName
,Department
,Salary
From plc2_employees e1
Inner Join Cte e2 On e1.Department = e2.Department
Order By
e1.Department
, e1.Salary desc
,e1.EmployeeID
is somehow not working... I am not getting the correct result. Could anyone please help me out.
Something like
select * from
(
select EmployeeID, EmployeeName, Department, Salary,
rank () over (partition by Department order by Salary desc) r
from PLC2_Employees
)
where r = 2
Edit - tested it and it gives the answer you expected.
If you're going to teach yourself how to deal with CONNECT BY, you should first find a problem that is suited to the construct. CONNECT BY is meant for processing data that's in a hierarchical form, which your example is not. Salaries are not related to each other in a hierarchical fashion. Trying to force-fit a construct on the wrong problem is frustrating and doesn't really teach you anything.
Take a look at the classic employee-manager relationship in the demo HR schema you can install with Oracle. All employees report to a manager, including managers (except the top guy). You can then use this schema to create a query to show, for example, the Organization Chart for the company.
START WITH … CONNECT BY is designed to explore data that forms a graph, by exploring all possible descending paths. You specify the root nodes in the START WITH clause and the node connections in the CONNECT BY clause (not in the WHERE clause).
The WHERE clause filters will be processed after the hierachical conditions, same for GROUP BY and HAVING (of course because GROUP BY is computed after WHERE).
Therefore you MUST here CONNECT BY PRIOR department = department for example. You must also avoid that a node connection is done between two salaries when there is an intermediate salary.
Therefore the final query would resemble this:
SELECT level
, Department
, Salary
FROM plc2_employees pe1
START WITH pe1.salary = (select max(salary) from plc2_employees pe2 WHERE pe2.Department = pe1.Department)
CONNECT BY PRIOR pe1.Department = pe1.Department
AND PRIOR pe1.Salary > pe1.Salary
AND PRIOR pe1.Salary = ( SELECT MIN(Salary) FROM plc2_employees pe3
WHERE pe3.Department = pe1.Department
AND pe3.Salary > pe1.Salary
)
The recursion condition states that there is no intermediate salary between the child row and the parent row.
Note that this will really be unefficient…
Try this, it gives second highest salary
select MAX(Salary) as Salary
from Employee_salary
where Salary not in (select MAX(Salary) from Employee_salary)
You can use this query:
select * from
employee e1
where 2 = (select count (distinct (salary))
from employee e2
where e2.salary >=e1.salary);
find out second highest salary from employee table having column as salary:
Database : DB2
with t as
(
select distinct salary from employee order by salary desc
),
tr as
(
select salary, row_Number() over() r from t
)
select salary from tr where r = 2
Try this,
It gives second highest salary...
select MAX(Salary) as Salary
from Employee_salary
where Salary not in (select MAX(Salary) from Employee_salary )
If you want to find nth highest salary than you can use following query....
you need to do just one change.....
Put the value of N=nth highest
Cheers....:)
SELECT * FROM Employee_salary Emp1
WHERE (N-1) = (SELECT COUNT(DISTINCT(Emp2.Salary))
FROM Employee_salary Emp2
WHERE Emp2.Salary > Emp1.Salary)
This will work -
SELECT MIN(Salary)
FROM employee
WHERE salary IN (SELECT TOP 2 salary FROM employee ORDER BY salary DESC)
First, select the distinct salaries in descending order (from greatest to least), from that set select the top 2 and put in ascending order (placing number 2 on top), then from those 2 select top 1:
select top 1 s.Salary
from
(select top 2 t.Salary
from
(select distinct Salary
from PLC2_Employees
order by Salary desc) t
order by Salary asc) s