I would like to find the difference between the average salary of the pilots and the average salary of the employees, including pilots, so basically a (average(pilot) - average(employees)).
Though I'm having trouble combining the two SQL queries together, here's what I've managed to do so far:
SELECT AVG(salary) AS 'average(pilot)'
FROM employees e, certified c
WHERE e.EID IN (SELECT EID FROM certified GROUP BY eid);
SELECT AVG(salary) AS 'average(employees)'
FROM employees e, certified c
WHERE e.EID NOT IN (SELECT EID FROM certified GROUP BY eid);
Now I only need to subtract the result of the second query from the first query. How do I proceed?
select (select query2) - (select query1);
I guess this should work,
select (select avg(salary) as 'average(employees)'
from employees e, certified c
where e.EID not in (select EID from certified group by eid)) - (select avg(salary) as 'average(pilot)'
from employees e, certified c
where e.EID in (select EID from certified group by eid));
Refer this for similar answers
Related
I want to print name and salary amount of the employee which has highest salary, till now its okay but if there are multiple records than print all. There are two table given :-
EMPLOYEE TABLE :-
SALARY TABLE:-
my query is: -
SELECT E.NAME, S.AMOUNT
FROM `salary` S,
employee E
WHERE S.EMPLOYEE_ID = E.ID
and S.AMOUNT = (SELECT max(`AMOUNT`)
FROM `salary`)
is there any better way to find out the solution ?
It is "with ties" functionality what you're trying to achieve. Unfortunately mySQL doesn't support that (in the docs there is nothing to add to the "LIMIT" part of the query), so you have no other option rather than looking for max salary first and filter records afterwards.
So, your solution is fine for that case.
Alternatively, if you're on version 8 and newer, you may move the subquery to the with clause
with max_sal as (
select max(amount) ms from salary
)
SELECT E.NAME, S.AMOUNT
FROM salary S
JOIN employee E
ON S.EMPLOYEE_ID = E.ID
JOIN max_sal ms
ON S.AMOUNT = ms.ms
or search for it in the join directly
SELECT E.NAME, S.AMOUNT
FROM salary S
JOIN employee E
ON S.EMPLOYEE_ID = E.ID
JOIN (select max(amount) ms from salary) ms
ON S.AMOUNT = ms.ms
But I'm sure it won't get you any better performance
I like solving them with a join:
WITH M as (select max(amount) as amount from salary)
SELECT E.NAME, S.AMOUNT
FROM M JOIN SALARY USING(AMOUNT) JOIN Employee USING(Id)
but your solution is perfectly fine..
I'm trying to answer these questions but I'm not understanding the whole joining and functions part of MySQL. Can someone show me or explain these to me?
this is the link to the employee database we are using - https://github.com/datacharmer/test_db
I want to know how many employees with each title were born after 1965-01-01.
I want to know the average salary per title.
How much money was spent on salary for the marketing department between the years 1990 and 1992?
This is what I have so far for each one.
1.
select count(title) as "Number Of Employees", title from titles GROUP BY title LIMIT 20;
SELECT d.dept_name as "Department", avg(s.salary) as "Average Salary" from departments d
INNER JOIN dept_emp de on de.dept_no = d.dept_no
INNER JOIN salaries s on s.emp_no = de.emp_no
GROUP BY d.dept_name;
and this one seems like it's just those two put together so I completely don't understand it.
Join with the employee table so you can get the employee's date of birth.
SELECT t.title, COUNT(*) AS "Number of Employees"
FROM titles AS t
JOIN employees AS e ON e.emp_no = t.emp_no
WHERE e.birth_date > '1965-01-01'
GROUP BY t.title
You need to get the most recent salary for each employee and average that. And you have to join with the titles table so you can average by title.
SELECT t.title, AVG(salary)
FROM titles AS t
JOIN employees AS e ON e.emp_no = t.emp_no
JOIN (
-- subquery to get latest salary for each employee
-- See https://stackoverflow.com/questions/7745609/sql-select-only-rows-with-max-value-on-a-column?noredirect=1&lq=1
SELECT s.emp_no, s.salary
FROM salaries AS s
JOIN (
SELECT emp_no, MAX(from_date) AS max_date
FROM salaries
GROUP BY emp_no
) AS ms ON s.emp_no = ms.emp_no AND s.from_date = ms.from_date
) AS s ON e.emp_no = t.emp_no
GROUP BY t.title
I'm not even sure what the third question means. Does it mean the total salaries for all employees during those years? This seems incredibly complex for a beginner exercise, since you have to deal with different start/end dates for employees, and changing salaries during that period. I'm not even sure how to do that in a single query.
I have a database for the airport.
I have one table named "employees" and one other table named "certified".
The "employees" table includes the names of all employees(pilot and other employees) and the staff code
named "eid" and the number of their salaries.
The certified table contains the pilot staff who specify which aircrafts they can fly.
WHAT I WANT: I want to subtract the average salary of pilots and the average salary of all employees(pilot and other employees).
I use this code:
Select AVG(salary) - (Select AVG(salary) from employees) as subtract
from employees as e,
certified as c
where e.eid = c.eid
but I have a problem :
As you can see in the "certified" table the "eid" of some pilots is repeated and affects the average value.
How can I use a salary only once in the calculation?
thank you in advance.
you can try something like below using SWITCH statement in MS Access
select
AVG(salary) - AVG( switch(IsPilot =1,salary,IsPilot=0,NULL)) as substract
from
(
select
distinct
e.eid,
e.salary,
Switch( c.eid is not null, 1 ,c.eid is NULL, 0) as IsPilot
from
employees e left join certified c
on e.id=c.eid )T
corresponding statement in MySql is
select
AVG(salary) - AVG( case when IsPilot =1 then salary when IsPilot=0 then NULL end) as substract
from
(
select
distinct
e.eid,
e.salary,
case when c.eid is not null then 1 when c.eid is NULL then 0 as IsPilot
from
employees e left join certified c
on e.id=c.eid )T
Use conditional aggregation:
SELECT AVG(e.salary) - AVG(CASE WHEN c.eid IS NOT NULL THEN e.salary END) as difference
FROM employees AS e
LEFT JOIN ( SELECT DISTINCT eid
FROM certified ) AS c ON e.eid=c.eid
First AVG calculates average salary over all rows, second - only for those rows (those employees) which have matched row(s) in certified table (all another rows have NULL for inner CASE, so they are not counted).
The query assumes that eid column is unique (maybe, primary key) in employees table.
PS. Maybe AVGs in the substraction must be swapped...
In MS Access this code may be
SELECT AVG(e.salary) - AVG(IIF(c.eid IS NOT NULL, e.salary, NULL)) as difference
FROM employees AS e
LEFT JOIN ( SELECT DISTINCT eid
FROM certified ) AS c ON e.eid=c.eid
I just started studying SQL queries.
I am practicing on this site: https://www.techonthenet.com/sql/joins_try_sql.php
I want to find:
"the name of the employee with the highest salary for every department".
My query is:
SELECT first_name, max(salary) FROM employees, departments
WHERE departments.dept_id=employees.dept_id
GROUP BY employees.dept_id
And I get null value for first_name :
I understand that the problem is due to the group by expressions. But how can I solve this?
Tables:
You can alternatively use row_number() like below, you don't need to join to departments table unless you need to show the name of the department:
Select e.*
from employees e
INNER JOIN
(
SELECT e.id, e.dept_id. e.first_name,
rn=row_number() over (partition by e.dept_id order by e.salary desc)
FROM employees e
) x ON x.id = e.id
where x.rn = 1
EDIT
(Since OP does not want to use row_number() function amd it turned out the query will be used in mysql instead of sql server) -> Can you please try this:
select em.*
from employees em, (
Select dept_id, max(salary) salary
from employees e
group by dept_id
) x on x.dept_id=em.dept_id and x.salary = em.salary
That should work but the online compiler does not accept join with a sub-query as far as I understand. Easiest solution I can think of, in this case:
select em.*
from employees em
where salary = (select max(salary) from employees em2 where em.dept_id = em2.dept_id)
SELECT top 2 first_name,max(salary) FROM employees, departments
WHERE departments.dept_id=employees.dept_id
GROUP BY first_name
order by max(salary) desc
try this:
SELECT e.first_name, e.salary FROM employees as e
INNER JOIN departments as d ON d.dept_id=e.dept_id
WHERE e.salary IN (SELECT max(salary) FROM employees GROUP BY dept_id)
Try this:
select first_name, b.dept_id, salary from employees a,
(
SELECT employees.dept_id, max(salary) as salary FROM employees, departments
WHERE departments.dept_id=employees.dept_id
GROUP BY employees.dept_id
)b where a.salary = b.salary and a.dept_id= b.dept_id
You can find the problem from here.
When there are multiple people with the highest salary in each department, the following SQL command output the expected results - all employees with highest salary are output:
select d.Name as Department, e.Name as Employee, e.Salary as Salary
from
(select Name, Salary, DepartmentId
from Employee
having (Salary, DepartmentId) in (
select max(Salary), DepartmentId
from Employee
group by DepartmentId)
)e, Department d
where e.DepartmentId = d.Id
However, the following command only output one employee even if there are multiple employees with the same highest salary:
select d.Name as Department, e.Name as Employee, e.Salary as Salary
from
(select Name, Salary, DepartmentId
from Employee
group by DepartmentId
having Salary = max(Salary)
)e, Department d
where e.DepartmentId = d.Id
Can anyone explain to me why the latter one does not work? Thanks!
The reason the second query doesn't work is because it's getting the max salary regardless of the department.
The way I would have done this, despite the valid first query (which is not using the standard JOIN syntax like it should), would be to first get the highest salary for each department like this:
SELECT departmentID, MAX(salary)
FROM employee
GROUP BY departmentID;
Once you have that, you can use a self join to only select the rows with that salary and department. This will include multiple people if they have the same salary:
SELECT e.*
FROM employee e
JOIN(
SELECT departmentID, MAX(salary) AS maxSalary
FROM employee
GROUP BY departmentID) tmp ON tmp.departmentID = e.departmentID AND tmp.maxSalary = e.salary
For further explanation, consider just the inner subquery you have:
SELECT name, department, salary
FROM employee
GROUP BY department
HAVING salary = MAX(salary);
The first problem with this is that you are selecting rows that are not consistent within your group. For each department id, you have multiple name values and multiple salary values, which will be chosen arbitrarily when you do the grouping. In my example, and the first, you can see that the grouping explicitly pulls the (departmentID, salary) pair for the max salary in each department, which the second one does not.
Here is an SQL Fiddle example to visually see the differences between your second query and mine.