Need SQL Query for the following data and Condition - sql

I have a table with Emp_salary name.
Table data
id name Slry
1 Ram 1500
2 janak 500
3 Anuj 400
4 Hardik 2000
5 Amit 2500
6 Atul 3000
7 Rahul 3500
8 Jay 4000
9 Parth 1500
10 Lalit 600
11 Ramesh 5000
My Que is : I will pass name of Emp in where condition.
And I want O/P like all Emp will come out that’s Salary will Less than that Emp’s salary(That I was pass in where condition)
Ex.
If i pass Lalit if i pass Atul
O/P will be like O/P will be like
name Slry name Slry
janak 500 janak 500
Anuj 400 Anuj 400
Lalit 600 Lalit 600
Ram 1500
Hardik 2000
Amit 2500
Atul 3000
Parth 1500
Don’t use “Sub Query” or “Function”
I need only Simple SQL Query for that.

You can use non-equality join:
WITH Src AS
(
SELECT * FROM (VALUES
(1 , 'Ram ', 1500),
(2 , 'janak ', 500 ),
(3 , 'Anuj ', 400 ),
(4 , 'Hardik', 2000),
(5 , 'Amit ', 2500),
(6 , 'Atul ', 3000),
(7 , 'Rahul ', 3500),
(8 , 'Jay ', 4000),
(9 , 'Parth ', 1500),
(10, 'Lalit ', 600 ),
(11, 'Ramesh', 5000)
)T(id, name, Slry)
)
SELECT S1.name, S1.Slry
FROM Src S1
JOIN Src S2 ON S1.Slry<=S2.Slry
WHERE S2.name='Lalit'

The best approach is to use a CTE to determine reference salary and then get only employees having a smaller salary than this salary by using a non-equality join.
DECLARE #empName as NVARCHAR(100) = 'Atul';
WITH cteRefEmp
AS
(
SELECT slry
FROM tmp.Emp
WHERE name = #empName
)
SELECT E.name, E.slry
FROM
tmp.Emp E
INNER JOIN cteRefEmp RE ON E.slry <= RE.slry

I found in this way also :
SELECT emp.name , emp.slry
from emp
WHERE emp.slry <= (SELECT slry FROM emp WHERE emp.name = 'Lalit')

Related

I need to construct table like below, dynamically using pivot or unpivot

EmpSalary table:
EmpCode BASIC HRA CONV
--------------------------
1 10000 500 300
2 10000 500 300
Desired output:
SalaryCode SalaryDetails
EmpCode 1
BASIC 10000
HRA 500
CONV 300
Total 10800
EmpCode 2
BASIC 10000
HRA 500
CONV 300
Total 10800
Actually we need what DBMS are you using.
The following code that includes unpivot clause works for Sql-Server or Oracle :
select SalaryCode, SalaryDetails
from
(select EmpCode, BASIC,HRA,CONV,
(BASIC+HRA+CONV) sub_Total
from EmpSalary
) p
unpivot
(SalaryDetails for SalaryCode in
(EmpCode,BASIC,HRA,CONV,sub_Total)
) unpvt;
Rextester Demo

Group by in PIVOT operator

How do i use the group by clause in the PIVOT operator?
I tried with the following code but i get the null values and the results are not getting aggregated.
select EmpName, CHN,HYD FROM location
PIVOT (Sum(salary) for EmpLoc in ([CHN], [HYD]))
AS
pivottable
I want the final output to be like this.
CHN HYD
kunder 400 200
shetty 150 150
or
CHN HYD Total
kunder 400 200 600
shetty 150 150 300
Total 550 350 900
Just add the derived column Total=CHN+HYD and a sub-query to create the Total Row
The Seq (though not displayed) will put the Total row at the bottom
Declare #YourTable table (EmpLoc varchar(25),EmpName varchar(25),Salary int)
Insert Into #YourTable values
('HYD','kunder',200)
,('HYD','shetty',150)
,('CHN','shetty',150)
,('CHN','kunder',200)
,('CHN','kunder',200)
Select EmpName, CHN,HYD,Total=CHN+HYD
From (
Select Seq=0,EmpLoc,EmpName,Salary From #YourTable
Union All
Select Seq=1,EmpLoc,'Total',Salary From #YourTable
) A
pivot (sum(Salary) for EmpLoc in ([CHN], [HYD])) P
Returns
EmpName CHN HYD Total
kunder 400 200 600
shetty 150 150 300
Total 550 350 900
Declare #YourTable table (EmpLoc varchar(25),EmpName varchar(25),Salary int)
Insert Into #YourTable values
('HYD','kunder',200)
,('HYD','shetty',150)
,('CHN','shetty',150)
,('CHN','kunder',200)
,('CHN','kunder',200)
;with cte as
(
SELECT * from
(
select * from #YourTable
) as y
pivot
(
sum(salary)
for EmpLoc in ([CHN], [HYD])
) as p
)
SELECT
EmpName,sum(CHN)CHN ,sum(HYD)HYD
FROM CTE
GROUP BY EmpName;
I have no issue using your code from your example to get your desired results. I am guessing that your query is not as simple as your example, and as such is introducing other complications not shown here.
You may need to use a subquery and pivot using just the columns necessary for the pivot and join back to the rest of your query to get the results you are looking for using pivot().
Using conditional aggregation may be a simpler solution:
select
empname
, CHN = sum(case when emploc = 'CHN' then salary else 0 end)
, HYD = sum(case when emploc = 'HYD' then salary else 0 end)
--, Total = sum(salary) /* Optional total */
from location
group by empname
rextester demo: http://rextester.com/LYRH81756
returns:
+---------+-----+-----+
| EmpName | CHN | HYD |
+---------+-----+-----+
| kunder | 400 | 200 |
| shetty | 150 | 150 |
+---------+-----+-----+

Pro rata basis bonus distribution using setup table

CREATE TABLE #empInfo(emp_id INT, dept_id INT, salary INT)
CREATE TABLE #empBonus(dep_id INT, emp_id INT, bonus INT)
I have above two tables for Employee and Bonus, where I will allocate bonus for the employees in bonus table every year but in example we are going to do it for a year only so the year column is not given.
INSERT INTO #empInfo VALUES
(111, 100, 5000),
(112, 100, 4000),
(113, 100, 4000),
(114, 100, 3500),
(115, 100, 4500),
(116, 100, 3000),
(114, 200, 3500),
(115, 200, 4500),
(116, 200, 3000),
(114, 300, 3500),
(115, 300, 3500),
(116, 300, 3500)
INSERT INTO #empBonus VALUES
(100, 111, 1000),
(100, NULL, 4000),
(100, 111, 500),
(100, NULL, 4000),
(100, 113, 700),
(200, 114, 600),
(200, NULL, 1600),
(300, 116, 900)
Above, If employee id defined in empBonus table then the bonus should allocated for that employee and if null that means bonus for all employees whose are not listed in the empBonus and will get bonus according to their salary.
we can define bonus for multiple employees and it can be multiple for same employee, in this case we have to sum total bonus and perform operation accordingly. Same case is for NULL.
For example, Base on formula given below, I have done below calculation in the EXCEL for easy understanding and in SQL I am trying with OUTER APPLY but not getting what I want from single query ?
--Formula = bonus*salary/totSalary(of respective group or employee)
DeptID EmpID TotBonus Salary TotSalary Bonus
100 111 1500 5000 5000 1500.00000000000
100 112 8000 4000 15000 2133.33333333333
100 113 700 4000 4000 700.00000000000
100 114 8000 3500 15000 1866.66666666666
100 115 8000 4500 15000 2400.00000000000
100 116 8000 3000 15000 1600.00000000000
200 114 600 3500 3500 600.00000000000
200 115 1600 4500 7500 960.00000000000
200 116 1600 3000 7500 640.00000000000
300 114 0 3500 7000 0.00000000000
300 115 0 3500 7000 0.00000000000
300 116 900 3500 3500 900.00000000000
Any help will be appreciated, thanks in advance :)
Here is one way using FULL OUTER JOIN and SUM() OVER() Window aggregate
;WITH cte
AS (SELECT ei.emp_id,ei.dept_id, eb.dep_id,
bonus = COALESCE(bonus, Max(CASE WHEN eb.emp_id IS NULL THEN bonus END)
OVER( partition BY COALESCE(ei.dept_id, eb.dep_id) )),
salary = Cast(salary AS NUMERIC(22, 6)),
TotSalary= Iif(eb.emp_id IS NULL, Sum(CASE WHEN eb.emp_id IS NULL THEN salary END)
OVER(partition by ei.dept_id), salary)
FROM #empInfo ei
FULL OUTER JOIN (SELECT bonus= Sum(bonus),
dep_id,
emp_id
FROM #empBonus
GROUP BY dep_id,
emp_id) eb
ON ei.dept_id = eb.dep_id
AND eb.emp_id = ei.emp_id)
SELECT emp_id,
bonus,
salary,
TotSalary,
( bonus * salary ) / NULLIF(TotSalary, 0)
FROM cte
WHERE emp_id IS NOT NULL
Result:
+--------+-------+-------------+-----------+--------------------+
| emp_id | bonus | salary | TotSalary | Bonus Distribution |
+--------+-------+-------------+-----------+--------------------+
| 111 | 1500 | 5000.000000 | 5000 | 1500.00000000000 |
| 112 | 8000 | 4000.000000 | 19000 | 1684.21052631578 |
| 113 | 8000 | 4000.000000 | 19000 | 1684.21052631578 |
| 114 | 8000 | 3500.000000 | 19000 | 1473.68421052631 |
| 115 | 8000 | 4500.000000 | 19000 | 1894.73684210526 |
| 116 | 8000 | 3000.000000 | 19000 | 1263.15789473684 |
+--------+-------+-------------+-----------+--------------------+
Well, that was a good challenge for me.
First, create a cte is to calculate the TotSalary column:
;With cteTotalSalary as
(
-- select total salary for employees that are in the bonus table
SELECT e.emp_id, dept_id, Salary, Salary As TotSalary
FROM #empInfo e
INNER JOIN #empBonus b ON e.dept_id = b.dep_id AND e.emp_id = b.emp_id
UNION
-- select total salary for employees that are in NOT the bonus table
SELECT e.emp_id, dept_id, Salary, SUM(Salary) OVER(PARTITION BY dept_id) As TotSalary
FROM #empInfo e
WHERE EXISTS (
SELECT 1
FROM #empBonus b
WHERE e.dept_id = b.dep_id
AND b.emp_id IS NULL
)
AND NOT EXISTS
(
SELECT 1
FROM #empBonus b
WHERE e.dept_id = b.dep_id
AND e.emp_id = b.emp_id
)
)
Then, query this cte twice with a union to get both types of bonuses (employee bonus and department bonus)
-- Get the bonus of the employess that exists in the empBonus table
SELECT c.emp_id, dept_id, SUM(Bonus) OVER(PARTITION BY c.emp_id) as Bonus, Salary, TotSalary, CAST(SUM(CAST(Bonus as decimal)) OVER(PARTITION BY c.emp_id) as decimal) as [Bonus Distribution]
FROM cteTotalSalary c
INNER JOIN #empBonus b ON c.dept_id = b.dep_id AND c.emp_id = b.emp_id
UNION
-- Get the bonus of the employees that does not exists in the empBonus table
SELECT c.emp_id, dept_id, SUM(Bonus) OVER(PARTITION BY c.emp_id), Salary, TotSalary, SUM(CAST(Bonus as decimal) * Salary / TotSalary) OVER(PARTITION BY c.emp_id)
FROM cteTotalSalary c
INNER JOIN #empBonus b ON c.dept_id = b.dep_id AND b.emp_id IS NULL
AND NOT EXISTS (
SELECT 1
FROM #empBonus b
WHERE c.dept_id = b.dep_id
AND c.emp_id = b.emp_id
)
Results:
emp_id dept_id Bonus Salary TotSalary Bonus Distribution
111 100 1500 5000 5000 1500.000000000
112 100 8000 4000 19000 1684.210526314
113 100 8000 4000 19000 1684.210526314
114 100 8000 3500 19000 1473.684210526
115 100 8000 4500 19000 1894.736842104
116 100 8000 3000 19000 1263.157894736
You can see it in action here

Sql query for Distinct names for max salary

1 shreya cpn 10000
2 shreya cpna 100000
3 shreya cpnaa 20000
4 preeti buld 30000
5 preeti bulda 20000
6 preeti buldan 25000
1 sushil mal 30000
1 sushil male 10000
1 sushil maleg 15000
9 abc ada 15000
this is my table...
and this is my query select * from stu where sal in (select MAX(sal)from stu group by name)
and ans is-
2 shreya cpna 100000
4 preeti buld 30000
1 sushil mal 30000
1 sushil maleg 15000
9 abc ada 15000
10 sss sfsfs 12000
its displaying 2 sushil...where i want only distinct names for that...
plzz give me suggestions...
If you need only name and salary columns in you output you can simply try this code:
select name, MAX(sal) from stu group by name
You can use columns in selection that you are grouping on as well as other columns with aggregated function.
In case you need all the other columns you will have to use join.
select s1.*
from stu s1
join (select name, MAX(sal) as sal from stu group by name) as s2
on s1.name = s2.name and s1.sal = s2.sal

rails. select records with max()

I have a table like this, and I want to return the top two person (by name) with the highest salary, and also the record with the corresponding salary. Here is the table
id, name, salary
1, Tom, 200
2, Tom, 300
3, Bob, 400
4, Bob, 500
5, Alice, 600
6, Alice, 700
I used this command
Employer.select("employers.*, max(employers.salary) as maxsalary").group("employers.name").order("maxsalary desc").limit(2)
Desired return:
id, name, salary
6, Alice, 700
4, Bob, 500
What I got seems to be like this:
id, name, salary
5, Alice, 600
3, Bob, 400
Is there anyway to select the records responding to the max ? Any comment/answer is much appreciated.
This Question is very tricky actually!
It seems very easy but it's not.
The Query:
Employer.joins(%Q|
LEFT JOIN employers as e
ON
e.name = employers.name
AND
employers.salary < e.salary
|).where('e.salary IS NULL').order('employers.salary DESC').limit(2)
HOW DOES THAT WORK! (I've been there)
We want to make sure that we only have the highest salary for each employer and then get the highest 2 of those.
Some Theoretical Stuff (skip this part if you only want to understand the query)
Let Salary be a function S(name,id) where it returns a value given the name and id
To prove that the given salary (S(name,id)) is the highest we have to prove that
We want to prove either
∀x S(name,id) > S(name,x) (this salary is higher than all other
salaries for that name)
OR
¬∃x S(name, id) < S(name, x) (there exists no higher salary for
that name)
The first approach will need us to get all the records for that name which I do not really like.
The second one will need a smart way to say there can be no record higher than this one.
Back to SQL
If we left joins the table on the name and salary being less than the joined table:
%Q|
LEFT JOIN employers as e
ON
e.name = employers.name
AND
employers.salary < e.salary
|
we make sure that all records that has another record with higher salary for the same user to be joined:
employers.id, employers.name, employers.salary, e.id, e.name, e.salary
1 , Tom , 200 , 2 , Tom , 300
2 , Tom , 300
3 , Bob , 400 , 4 , Bob , 500
4 , Bob , 500
5 , Alice , 600 , 6 , Alice , 700
6 , Alice , 700
That will help us filter for the highest salary for each employer with no grouping needed:
where('e.salary IS NULL')
employers.id, employers.name, employers.salary, e.id, e.name, e.salary
2 , Tom , 300
4 , Bob , 500
6 , Alice , 700
Now all we need to do is sort:
order('employers.salary DESC')
employers.id, employers.name, employers.salary, e.id, e.name, e.salary
6 , Alice , 700
4 , Bob , 500
2 , Tom , 300
Then limit
limit(2)
employers.id, employers.name, employers.salary, e.id, e.name, e.salary
6 , Alice , 700
4 , Bob , 500
And that's the answer we need.
Why don't we
1.
Employer.order('salary desc').limit(2)
Because this will get us the records with the highest salaries independent of the name
employers.id, employers.name, employers.salary
5 , Alice , 600
6 , Alice , 700
2.
Employer.select('DISTINCT(name)').order('salary desc').limit(2)
The problem with that is it will only keep the first appearance of the name then sort
employers.id, employers.name, employers.salary
1 , Tom , 200
3 , Bob , 400
5 , Alice , 600