I'm trying to increase the salary for those employees who treat at least 2 patients by 10%. My problem is that the salary first multiplies by 2 for every patient they treat and then multiplies by 10% at the end. For exampel if the employee earns 25.000 and treats 3 people the new salary becomes 82.500.
select distinct t.empNbr, e.Salary, sum(e.Salary*1.1) as NewSalary from Treats t
inner join Employee e
on e.empNbr=t.empNbr
WHERE t.empNbr IN
(
SELECT empNbr
FROM Treats
GROUP BY empNbr
HAVING COUNT(*) >= 2)
group by t.empNbr, e.Salary
CROSS APPLY should help:
SELECT e.empNbr,
e.Salary,
e.Salary*1.1 as NewSalary
FROM Employee e
CROSS APPLY (
SELECT empNbr
FROM Treats
WHERE e.empNbr = empNbr
GROUP BY empNbr
HAVING COUNT(*) > 1
) as t
The t part gets empNbr we need. Then we select empNbr and salary from Employee table and do math :)
One more way:
SELECT TOP 1 WITH TIES
e.empNbr,
e.Salary,
e.Salary*1.1 as NewSalary
FROM Employee e
INNER JOIN Treats t
ON e.empNbr = t.empNbr
ORDER BY
CASE WHEN COUNT(t.empNbr) OVER (PARTITION BY t.empNbr ORDER BY t.empNbr) > 1 THEN 1 ELSE 0 END DESC,
ROW_NUMBER() OVER (PARTITION BY t.empNbr ORDER BY t.empNbr)
This should be the right query. Let me know if this works
select empNbr, Salary, sum(Salary*1.1) as NewSalary
from employee
where empNbr in (select empNbr
from Treats
group by empNbr
having count(*) >=2) ----- Ordered as a code
Christopher, You can use below query to get the result,
SELECT t.empNbr,
e.Salary,
(e.Salary * e.count +(e.Salary/10) ) as NewSalary
from Treats t
INNER JOIN
(SELECT empNbr, COUNT(*) AS count Employee GROUP BY empNbr) e
ON e.empNbr=t.empNbr
AND e.count >=2
Explination
1. We can calculate result without having clause2.In the inner join, empNbr and the count of that employee in derived3.Using this count in the select query, the current salary is multiplied and 10% is added with the salary
Hope this is what you need. Any issues, feel free to ask
Related
enter image description here
select Fname,Lname,salary,ssn
from Employee
where joptype='nurse' AND salary <= ALL (select salary
from Employee E,Nurses N
where E.Ssn=N.Ssn AND E.joptype='nurse' AND N.shift='morning')
I want to return a list of nurses name who works at morning and their salary is less than all nurses, or the opposite. I've tried both morning and night, also I've tried greater than all nurses. I think the problem is in the second where it seems like he ignores the shift condition.
You can use EXISTS to find the morning shifts and, from Oracle 12, you can use ORDER BY salary ASC FETCH FIRST ROW WITH TIES to find the matching employees with the lowest salary:
SELECT Fname,
Lname,
salary,
ssn
FROM Employee e
WHERE jobtype='nurse'
AND EXISTS( SELECT 1
FROM Nurses N
WHERE E.Ssn=N.Ssn
AND N.shift='morning' )
ORDER BY salary ASC
FETCH FIRST ROW WITH TIES;
or, if you want to check all nurses and find the minimum salary and then filter on morning shifts:
SELECT *
FROM (
SELECT Fname,
Lname,
salary,
ssn
FROM Employee
WHERE jobtype='nurse'
ORDER BY salary ASC
FETCH FIRST ROW WITH TIES
) e
WHERE EXISTS( SELECT 1
FROM Nurses N
WHERE E.Ssn=N.Ssn
AND N.shift='morning' )
If you want to use a JOIN, rather than EXISTS, then you can use:
SELECT e.Fname,
e.Lname,
e.salary,
e.ssn
FROM (
SELECT Fname,
Lname,
salary,
ssn
FROM Employee
WHERE jobtype='nurse'
ORDER BY salary ASC
FETCH FIRST ROW WITH TIES
) e
INNER JOIN Nurses N
ON E.Ssn=N.Ssn
WHERE N.shift='morning'
(However, if there are multiple entries in Nurses for an Employee then you will get duplicates using a JOIN that you would not get using EXISTS)
Or for your code, you appear to have the filter for shifts in the wrong place:
SELECT e.Fname,
e.Lname,
e.salary,
e.ssn
FROM Employee e
INNER JOIN Nurses n
ON (e.Ssn = n.Ssn)
WHERE e.jobtype='nurse'
AND n.shift='morning'
AND e.salary <= ALL ( SELECT salary
FROM Employee
WHERE jobtype='nurse' );
fiddle
This is how I understood it; what you said:
their salary is less than all nurses
probably means their average salary, so I used it in a subquery.
select e.fname, e.lname, e.salary, e.ssn
from employee e join nurse n on e.ssn = n.ssn
where e.joptype = 'nurse'
and n.shift = 'morning'
and salary < (select avg(salary) --> average salary of all nurses
from employee
where joptype = 'nurse'
);
(Just a remark: is it really joptype? Is it not a job?)
Maybe you could try it like here:
select
Fname, Lname, salary, ssn
from
Employee
where
joptype='nurse' AND
salary <= ( Select MIN(salary)
From Employee E
Inner join Nurses N ON(E.Ssn=N.Ssn)
Where E.joptype = 'nurse' AND
N.shift = 'morning'
)
... this will give you the list of nurses with salary less than or equal to the minimum salary among morning nurses..
I have to display the employee detail who has got the maximum bonus(one with employee details and another table with bonus details). Here I have created a 'performance bonus' column to sum up the multiple bonuses. How to retrieve the employee from that column?
select e.Employee_id,
e.First_name,
e.Department,
e.Salary,
coalesce((select sum(b.Bonus_Amount)
as Bonus-- Let's sum up all Employee's the bonuses
from Employee_Bonus_Table b
where b.Employee_ref_id = e.Employee_Id), 0) [Performance_bonus]
from Employee_Table e
If I understood the task correctly, then the bonuses can be repeated, is that right?
then we must first sum up all the bonuses by employee, then sort from largest to smallest and get the first one from the list
--- for examples:
with Employee_Bonus_Table as(
select Bonus_Amount = 1 ,Employee_ref_id = 1
union select Bonus_Amount = 1000 ,Employee_ref_id = 2
union select Bonus_Amount = 2000 ,Employee_ref_id = 2
),Employee_Table as (
select Employee_id=1
,First_name='First_name'
,Department= 'Department'
,Salary = 1000
UNION select Employee_id=2
,First_name='First_name2'
,Department= 'Department2'
,Salary = 2000
)
--reslut query:
select top 1
e.Employee_id,
e.First_name,
e.Department,
e.Salary,
b.sumBonus_Amount
from Employee_Table e
join (select sumBonus_Amount = sum(Bonus_Amount), Employee_ref_id
from Employee_Bonus_Table
group by Employee_ref_id
) b on b.Employee_ref_id = e.Employee_Id
order by b.sumBonus_Amount desc
i have two tables
employee :
employee_number employee_name salary divison_id
division :
division_id division_name
How to Show division id, division name, number of employees working in each division that has the highest number of employees.
I want to have an outcome like this :
division_id division_name total_employee
Z-100 | finance | 3
SELECT *
FROM (SELECT e.division_id,
d.division_name,
Count(1) total_employee
FROM employee e
JOIN division d
ON e.division_id = d.division_id
GROUP BY e.division_id
ORDER BY Count(1) DESC)a
LIMIT 1
If you want all the department with most employees you should consider that more than one department can have that. So I am revising my answer and instead of top I am using Rank() with CTE to get all the divisions with most number of employees.
with DivisionWithMostEmployee as
(
select Rank()over(order by count(*) desc) RowNumber, d.division_id, d.division_name, count(*) TotalEmployee
from division d, employee e where d.division_id=e.division_id
group by d.division_id,d.division_name
)
select Division_id,Division_name,TotalEmployee from DivisionWithMostEmployee where RowNumber=1
I have an Employee table with Salary. I want to list Salary - Avg(Salary) for every Employees. Can someone please help me with the SQL query for the same.
You can do this using window functions:
select e.*,
(salary - avg(salary) over ()) as diff
from employees e;
You could use an inline view to return a single row with the average salary. and join that row back to employee table.
Something like this:
SELECT e.emp_id
, e.salary
, e.salary - a.avg_salary
FROM employee e
CROSS
JOIN ( SELECT AVG(t.salary) AS avg_salary
FROM employee t
) a
ORDER BY e.emp_id
Just a couple other variations; the others already posted should serve the purpose quite well -- assuming we've all correctly inferred the desired output, given no DDL nor sample data, nor the expected output from the given inputs.
If there is no requirement to include the averaged salary [as the average over all rows] in addition to the calculated difference, then the following [shown with an optional casting to a decimal result] uses a scalar subselect to get the value to subtract from each employee salary:
select emp.*
, dec( salary - ( select avg(salary)
from employee_table )
, 11, 0 ) as saldif
from employee_table as emp
Or to use the averaged salaries in both the difference and as a column by itself, then again the scalar subselect, but made available for lateral reference in the [explicitly joined-to] subquery; again, optional casting for decimal results:
select x.*
from table
( select avg(salary)
from employee_table
) as a ( avgsal )
cross join lateral
( select emp.*
, dec( salary - avgsal , 11 ) as saldif
, dec( avgsal , 11 ) as salavg
from employee_table as emp
) as x
other solution ;)
with avgsalary as (
select avg(salary) avgsal from employee_table
)
select emp.*, case when emp.salary is null then cast(null as decimal) else round(emp.salary - avgs.avgsal, 2) end as diffsal, avgs.avgsal
from employee_table as emp cross join avgsalary avgs
And even another variation:
with EmpAvg (avgSalary)
as ( SELECT avg( salary ) from employee_table )
select e.*, a.avgSalary,
(e.salary - a.avgSalary) as diffAvg
from employee_table e cross join EmpAvg a
There may be many forms of queries that can give equivalent results. (Although I left off casting the calculated values, so not exactly equal result values.)
I can get the count of employees and avg salary but when I try to get the the addition select of listing the number of employees paid below the average it fails.
select count(employee_id),avg(salary)
from employees
Where salary < avg(salary);
select count(*), (select avg(salary) from employees)
from employees
where salary < (select avg(salary) from employees);
The problem is that AVG is an aggregation function. SQL is not smart enough to figure out how to mix aggregated results within the rows. The traditional way is to use a join:
select count(*), avg(e.salary),
sum(case when e.salary < const.AvgSalary then 1 else 0 end) as NumBelowAverage
from employees e cross join
(select avg(salary) as AvgSalary from employees) as const
select TotalNumberOfEmployees,
AverageSalary,
count(e.employee_id) NumberOfEmployeesBelowAverageSalary
from (
select count(employee_id) TotalNumberOfEmployees,
avg(salary) AverageSalary
from employees
) preagg
left join employees e on e.salary < preagg.AverageSalary
group by TotalNumberOfEmployees,
AverageSalary
Note: I used a LEFT join so if you had 3 equal employees, it would show 0 instead of no results (nobody below below average).
It isn't clear which columns you want in your result set, which makes it difficult to answer your question. Making the question clear improves the quality of the answers.
You seem to want 3 facts:
Number of employees.
Average salary.
Number of employees earning less than the average salary.
And you show a query which does the job for the first two facts:
SELECT COUNT(*) AS NumberOfEmployees,
AVG(Salary) AS AverageSalary
FROM Employees
What's the difference between COUNT(*) and COUNT(Employee_ID)? The difference is that the latter only counts the rows where there is a non-NULL value in the Employee_ID column. A good optimizer will recognize that Employee_ID is a primary key and contains no NULL values, and the query will be the same. But COUNT(*) is more conventional and less reliant on the optimizer.
The other statistic can be generated as a simple value in the select-list via a sub-query:
SELECT COUNT(*) AS NumberOfEmployees,
AVG(Salary) AS AverageSalary,
(SELECT COUNT(*)
FROM Employees
WHERE Salary < (SELECT AVG(Salary) FROM Employees)
) AS NumberOfEmployeesPaidSubAverageWages
FROM Employees
Under many circumstances, it would not be appropriate to write the sub-query like that, but for the interpretation of the specified query, it is fine.
select * from <table name> where salary < (select avg(<salary column name) from <table name>);
Example:
select * from EMPLOYEE where sal < (select avg(emp_sal) from EMPLOYEE);
SELECT e.ename,e.deptno,e.sal,d.avg
FROM emp e,(SELECT deptno, avg(sal) avg
FROM emp
GROUP BY deptno) d
WHERE e.deptno=d.deptno
AND
e.sal < d.avg