Second Highest Salary without subquery - sql

EmployeeID EmployeeName Department Salary
----------- --------------- --------------- ---------
1 Nisha Finance 40000.00
2 John Finance 25000.00
3 NEo Finance 25000.00
4 Dan Finance 15000.00
5 Jstin IT 80000.00
6 Amy IT 50000.00
I want to get the second highest Salary which is 50000.00 without using subquery?

Try below query, it will work.
select max(e1.salary) from Employee e1,Employee e2 where e1.salary<e2.salary;

Using limit and offset (to skip highest salary)
In MySQL
select * from table order by Salary desc limit 1 offset 1
In SQL server
select * from table order by Salary desc offset 1 rows fetch next 1 row only
You can try with another Database here
http://sqlfiddle.com/#!9/15c32/1/0

Couldn't you just use LIMIT 1,1 (grab first result after first row). I come from the MySql side of things so the sql might have to be adjusted slightly for Sql Server.
SELECT Salary FROM table ORDER BY Salary DESC LIMIT 1,1

SELECT DISTINCT Salary
FROM TABLE
ORDER BY Salary DESC OFFSET 1 ROWS
FETCH NEXT 1 ROW ONLY

Test this query after adding your table name and column names
select MAX(country) as country from users where country < ( select MAX(country) as country from users where country < (SELECT MAX(country) from users ) );

You can use TOP keyword to fetch number of records from the database tables. for example
SELECT TOP 1 * FROM TABLE NAME

Related

SQL: finding the maximum average grouped by an ID

Consider following dataset:
id
name
mgr_id
salary
bonus
1
Paul
1
68000
10000
2
Lucas
2
29000
null
3
Max
1
50000
20000
4
Zack
2
30000
null
I now want to find the manager who pays his subordinates the highest average salary plus bonus. A manager is someone who is present in of the mgr_id cells. So in this example Paul and Lucas are managers because their id is present in the mgr_id column of themselves and Max for Paul and Zack for Lucas.
Basically I want MAX(AVG(salary + bonus)) and then grouped by the mgr_id. How can I do that?
I am using SQLite.
My expected output in this example would be simply the employee name 'Paul' because he has 2 subordinates (himself and Max) and pays them more than the other manager Lucas.
SELECT
mrg_id
, pay_avg
FROM
(
SELECT mrg_id
, AVG(salary + COALESCE(bonus,0)) pay_avg
FROM <table>
GROUP
BY mrg_id
) q
ORDER
BY pay_avg
desc
LIMIT 1
select top 1 t1.mgr_id,AVG((t1.salary)+(t1.bonus)) as tot_sal
from #tbl_emps as t1
group by t1.mgr_id
order by AVG((t1.salary)+(t1.bonus)) desc

Reconciliation Automation Query

I have one database and time to time i change some part of query as per requirement.
i want to keep record of results of both before and after result of these queries in one table and want to show queries which generate difference.
For Example,
Consider following table
emp_id country salary
---------------------
1 usa 1000
2 uk 2500
3 uk 1200
4 usa 3500
5 usa 4000
6 uk 1100
Now, my before query is :
Before Query:
select count(emp_id) as count,country from table where salary>2000 group by country;
Before Result:
count country
2 usa
1 uk
After Query:
select count(emp_id) as count,country from table where salary<2000 group by country;
After Query Result:
count country
2 uk
1 usa
My Final Result or Table I want is:
column 1 | column 2 | column 3 | column 4 |
2 usa 2 uk
1 uk 1 usa
...... but if query results are same than it shouldn't show in this table.
Thanks in advance.
I believe that you can use the same approach as here.
select t1.*, t2.* -- if you need specific columns without rn than you have to list them here
from
(
select t.*, row_number() over (order by count) rn
from
(
-- query #1
select count(emp_id) as count,country from table where salary>2000 group by country;
) t
) t1
full join
(
select t.*, row_number() over (order by count) rn
from
(
-- query #2
select count(emp_id) as count,country from table where salary<2000 group by country;
) t
) t2 on t1.rn = t2.rn

calculate highest nth salary using sql

I want to calculate highest nth salary in Oracle. I've already done with my solution but on google I found one query doing the same thing.
Here is the query
SELECT *
FROM Employee Emp1
WHERE (N - 1) = (SELECT COUNT(DISTINCT(Emp2.orig_salary))
FROM Employee Emp2
WHERE emp2.orig_salary > emp1.orig_salary)
Data
ID Name Birth Orig_Salary
2 John 15-JUL-97 2341
3 Joe 25-JAN-86 4321
4 Tom 13-SEP-06 2413
5 Jane 17-APR-05 7654
6 James 18-JUL-04 5679
7 Jodd 20-JUL-03 5438
8 Joke 01-JAN-02 8765
9 Jack 29-AUG-01 7896
I'm not not able to understand this query.
After running inner query it will always gives me count of 8 after doing this it will go to where clause where it will pick salary which is higher than the outer query salary. How equal operator is working here in between inner and outer query and how comparison is happening.
Could any help me to understand how this query is working technically in back-end..?
SELECT *
FROM Employee Emp1
WHERE (N - 1) = (SELECT COUNT(DISTINCT(Emp2.orig_salary))
FROM Employee Emp2 <--- cartesian product with same table
WHERE emp2.orig_salary > emp1.orig_salary) <---- but do the cartesian product only if line of salary of emp 2 is greater than the current line of Emp1 'salary
e.g assume there are only 3 lines in the table:
ID Name Birth Orig_Salary
2 John 15-JUL-97 2341
3 Joe 25-JAN-86 4321
4 Tom 13-SEP-06 5413
the main query will look at the first line --> 2 John 15-JUL-97 2341 <---, and subquery will return 2 because the salaries 4321 (emp2.orig_salary) and 5413 (emp2.orig_salary) are greater than 2341 (emp1.orig_salary)
the main query will then look at the second line --> 3 Joe 25-JAN-86 4321 <---, and subquery will return 1 because the salaries 5413 (emp2.orig_salary) is greater than 2341 (emp1.orig_salary)
when i say subquery, it is the
=(SELECT COUNT(DISTINCT(Emp2.orig_salary))
FROM Employee Emp2 <--- cartesian product with same table
WHERE emp2.orig_salary > emp1.orig_salary)
and the main query is
SELECT *
FROM Employee Emp1
WHERE
the returned value from the subquery is then compare to the where condition n-1, if the condition is satisfied, then it retrieves the line.
There is no need to understand that query. The correct formulation is:
SELECT Emp1.*
FROM (SELECT Emp1.*, DENSE_RANK() OVER (ORDER BY Emp2.orig_salary) as seqnum
FROM Employee Emp1
) Emp1
WHERE seqnum = <n>;
This gives the details for the employees. If you just want the salary:
SELECT orig_salary
FROM (SELECT Emp1.*, DENSE_RANK() OVER (ORDER BY Emp2.orig_salary) as seqnum
FROM Employee Emp1
) Emp1
WHERE seqnum = <n> AND rownum = 1;
I should note that a simpler version of this is:
select distinct orig_salary
from employees
order by orig_salary desc
offset <n - 1>
fetch first 1 row only;
The use of a correlated subquery for this is a pleasant anachronism from the days when relational databases were not as powerful as they are now. It is of historical interest.

logic behind SQL code not clear

I have come across an SQL code as below
SELECT DISTINCT FLD1, FLD2, FLD3, FLD4 FROM
TBL1 WHERE FLD1 = 'MFG' AND FLD2 = '1'
My doubt is on the DISTINCT keyword here applied before FLD1. There is a filtration condition to select only those records where FLD1 = 'MFG'. So does the distinct make any difference there?
I have run the same SQL without the DISTINCT and the number of records retrieved is the same with the DISTINCT.
This is written for DB2 database on iSeries.
it eliminates all the duplicate records and fetch only unique records.
example:
Table Employee
Id Name Salary
1 Alex 2000
2 Alxender 1000
3 Paul 2000
4 Alex 2000
select distinct Salary
from Employees;
it will return:
Salary
2000
1000
select distinct Name,Salary
from Employees;
will return:
Name Salary
Alex 2000
Alxender 1000
Paul 2000
The query:
select distinct Salary,Name
from Employees
where salary = 2000;
will return:
Name Salary
Alex 2000
Paul 2000

Is it possible to SELECT N first rows from database using ROWNUM if some rows have the same value?

I'm trying to select N first rows from a database using ROWNUM. The problem is that if I want to select 6 first values of age with names of people with this age and some of the have the same value of age not every person will be shown.
For example
name age
Peter 15
Mark 22
Kelly 17
Mike 17
George 17
If I want to show people with 2 biggest values of age ROWNUM will show Mark and Kelly or Mike or George. Not all three of them. The expected result is:
Name age
Mark 22
Kelly 17
Mike 17
George 17
Is it possible to get this result using ROWNUM? Not RANK, DENSE_RANK, JOIN, correlated subquery but ROWNUM?
You can try something like this:
select *
from test
where age in (
select age
from (
select age
from test
group by age
order by age desc
)
where rownum <=2
)
The right solution dense_rank(), but you can do it with just row_number() and some subqueries:
select t.*
from t
where t.age in (select age
from (select age
from t t2
order by age desc
) x
where rownum <= 2
);
In Oracle 12+, you can simplify this:
select t.*
from t
where t.age in (select age
from t t2
order by age desc
fetch first 2 rows only
);