Averaging salary by location across two tables - mysql

There are two tables, one with the employees salary and another with the department.
table1:
employee_id name salary
--------------------------------------
01 K.Irving 30000
02 J.Polk 50000
03 S.Smith 20000
04 D.Rai 35000
table2:
employee_id name department
------------------------------------------
01 K.Irving marketing
02 J.Polk finance
03 S.Smith marketing
04 D.Rai it
I would like to find out how to find the average salary per department where it is lower than 40000
Ideally it should look like this:
avg_salary department
-----------------------------
35000 it
25000 marketing
So far I have tried to combine the two tables using the following formula, however I am having trouble putting in the conditions I wanted:
SELECT table1.employee_id
, table1.name
, table1.salary
, table2.department
FROM table1
LEFT
JOIN table2
ON table1.employee_id = table2.employee_id
AND table1.employee_name = table2.employee_name
ORDER
BY salary DESC;
The solution would be a mixture of the above and below, I was not sure how to combine the two.
SELECT AVG(salary), department
FROM table1, table2
GROUP BY department
HAVING AVG(salary) <40000
ORDER BY salary DESC;
I was not sure how to get the averages per department, when I used the code above it took an average of all salaries.

You need to GROUP BY the department and limit the results with a HAVING clause.
SELECT avg(e.salary) avg_salary,
d.department
FROM table2 d
LEFT JOIN table2 e
ON e.employee_id = d.employee_id
GROUP BY d.department
HAVING avg(e.salary) < 4000
ORDER BY e.salary DESC;
But note, that your design is bad. There should be a table for the departments, that only stores the departments, not any employees to it. Then there should be a linking table with just a user and a department ID to store which employees is in which department. There should not be the employee (or the department) name in that table.

A LEFT JOIN is unnecessary for this problem. In order for the average to be well-defined, you need to have matches between the tables. Hence:
SELECT avg(e.salary) as avg_salary,
d.department
FROM table2 d JOIN
table2 e
ON e.employee_id = d.employee_id
GROUP BY d.department
HAVING avg_salary < 4000
ORDER BY e.salary DESC;
As a convenience, you can also use the column alias in the HAVING clause.

Related

how to calculate total business added by the employees individually

I have two tables like employees and doctorsrating.
In employees table contains list of registered employees with columns of emp_bioid and emp_name and doctorspoints emp_bioid, points, pointsname, doctor_name, createdAt of columns.
Employees will add points for doctors which will stored by the emp_bioid. My question is i want to count total records added by the each and every employees.
I have tried this query but the business count was wrong.
SELECT emp_bioid, COUNT(*) as Doctor (SELECT emp_name from employees where emp_bioid = doctorsrating.emp_bioid) as emp_name FROM doctorsrating
WHERE createdAt between '2021-03-01' AND '2021-03-24' GROUP BY emp_bioid
You can make a join and group by both columns (id and name) as below:
SELECT e.emp_bioid, e.emp_name, COUNT(*)
FROM employees e
JOIN doctorsrating dr ON e.emp_bioid = dr.emp_bioid
WHERE dr.createdAt between '2021-03-01' AND '2021-03-24' GROUP BY e.emp_bioid, e.emp_name

Merging tables and getting the output in ascending order

I have two tables as such:
student department
id department_id department_id department_name
5 5 5 Computer Science
1 4 4 Architecture
3 2 1 Mathematics
4 5 3 Chemistry
2 4 2 Physics
I wrote a query as follow and got the following results.
SELECT DEPARTMENTS.DEPT_NAME AS D, STUDENTS.DEPT_ID AS D_ID
FROM STUDENTS
INNER JOIN DEPARTMENTS
ON STUDENTS.DEPT_ID=DEPARTMENTS.DEPT_ID ;
Computer Science 5
Computer Science 5
Physics 2
Architecture 4
Architecture 4
It's fine till here but I want something like
Computer Science 2
Architecture 2
Physics 1
Chemistry 0
Mathematics 0
i.e department name , num_of students where num_of students are in decending order.
What can I add to the query?
I would use COUNT(*) and subquery it for the ORDER BY
SELECT * FROM (
SELECT DEPARTMENTS.DEPT_NAME, COUNT(*) AS num_ofstudents
FROM STUDENTS
LEFT JOIN DEPARTMENTS
ON STUDENTS.DEPT_ID=DEPARTMENTS.DEPT_ID
GROUP BY Departments.Dept_name
) AS a ORDER BY num_ofstudents
edit- Thanks AaronDietz for pointing this out!
You should replace the INNER JOIN with a LEFT JOIN so that the query includes the records from [Departments] that do not have any students. Also, I did not need to include the subquery.
SELECT DEPARTMENTS.DEPT_NAME, COUNT(*) AS num_ofstudents
FROM STUDENTS
LEFT JOIN DEPARTMENTS
ON STUDENTS.DEPT_ID=DEPARTMENTS.DEPT_ID
GROUP BY Departments.Dept_name
ORDER BY num_ofstudents
You can try grouping the departments and the id, then count.
SELECT DEPARTMENTS.DEPT_NAME AS D, COUNT(*) as NID
FROM STUDENTS
INNER JOIN DEPARTMENTS
ON STUDENTS.DEPT_ID=DEPARTMENTS.DEPT_ID
GROUP BY DEPARTMENTS.DEPT_NAME
ORDER BY NID DESC
I think the simplest approach is to select the departments and get the count in a subquery:
select
department_id,
department_name,
(select count(*) from student s where s.department_id = d.department_id) as student_count
from department d
order by 3 desc;
This works well, because you just want one value from the students, namely the count. If you wanted more information then you'd move the subquery to the from clause. E.g.:
select
d.department_id,
d.department_name,
colalesce(s.students, 0) as student_count,
s.ids as student_ids
from department d
left join
(
select
department_id,
count(*) as students,
group_concat(id) as ids
from student
group by department_id
) s on s.department_id = d.department_id
order by 3 desc;
SELECT DEPARTMENTS.DEPT_NAME AS D, count(STUDENTS.DEPT_ID) AS D_ID
FROM STUDENTS
INNER JOIN DEPARTMENTS
ON STUDENTS.DEPT_ID=DEPARTMENTS.DEPT_ID
GROUP BY D
ORDER BY D_ID DESC;
Grouping by department name
Other queries are mostly right but COUNT should be on student id and query should start from department instead of student.
SELECT DEPARTMENTS.DEPT_NAME,
COUNT(id) AS num_ofstudents
FROM DEPARTMENT
LEFT JOIN students ON STUDENTS.DEPT_ID = DEPARTMENTS.DEPT_ID
GROUP BY DEPARTMENTS.DEPT_NAME
ORDER BY num_ofstudents

Department name and number of students

I found one question in MySQL I am trying. Please tell me if following solution will work or is there any better solution?
select D.DEPT_NAME, COUNT(*)
from Departments D
left outer join STUDENTS S
on S.Dept_ID = D.Dept_ID
group by D.DEPT_NAME
order by 2 desc, 1
Students table has following fields:
Student_ID
Student_Name
Gender
Dept_ID
Departments table has following fields:
Dept_ID
Dept_Name
A university uses 2 data tables, Students and Departments, to store data
about its students and the departments associated with each major.
Write a query to print the respective department name and number of students
majoring in each department for all departments in the Departments table
(even ones with no current students).
Sort your results by descending number of students; if two or more departments have same number of students, then sort those departments alphabetically by department name.
Forgive me altering the formatting of the code.
I would change the ORDER BY, as follows:
SELECT
d.DEPT_NAME,
COUNT(s.STUDENT_ID)
FROM
Departments d
LEFT JOIN Students s ON d.DEPT_ID = s.DEPT_ID
GROUP by
d.DEPT_ID
ORDER by
COUNT(s.STUDENT_ID) DESC,
d.DEPT_NAME ASC
You need a way to count the students in each department, then you need a way to list all departments, even those without students.
Counting the students in each department: (http://sqlfiddle.com/#!15/39a8b/15/0)
SELECT Dept_ID, COUNT(*) Students
FROM STUDENTS
GROUP BY Dept_ID
Then, treating that as a subquery, left join it to your other table. (http://sqlfiddle.com/#!15/39a8b/16/0)
SELECT D.DEPT_NAME, S.Students
FROM Departments D
LEFT JOIN (
SELECT Dept_ID, COUNT(*) Students
FROM STUDENTS
GROUP BY Dept_ID
) S ON D.Dept_ID = S.Dept_ID
The LEFT JOIN preserves rows in the DEPARTMENTS table that don't match the ON clause. This gets you stuff like this.
Biology 7
Mathematics (NULL)
Sociology 11
Physics 3
So you have to deal with that (NULL) problem. Here's how. Change the SELECT to say
SELECT D.DEPT_NAME, IFNULL(S.Students,0)
It's a little tricky to join a table to an aggregate where the aggregate (the COUNT/GROUP BY query) has missing data. But that's how you do it.
You can figure out the ORDER BY stuff on your own.
SELECT d.department_name, COUNT(s.student_name) AS student_count
FROM student s
LEFT JOIN department d
ON s.department_id = d.department_id
GROUP BY department_name
ORDER BY d.department_name;
!!This is finally the correct answer !!
Don't hardcode the problem please stay tuned and work like professional
Excute below.
SELECT
ad.Dept_Name,
count(ass.Student_Id) as Stduent_Enrolled
FROM [Alok.Departments] ad
Left Outer Join [Alok.Students] ass
ON ad.Dept_ID = ass.Dept_ID
Group by ad.Dept_Name
ORDER by
CASE WHEN COUNT(ad.Dept_ID) >=2
THEN ad.DEPT_NAME END desc,
CASE WHEN COUNT(ad.Dept_ID) < 2
THEN ad.DEPT_NAME END asc
1 select department_name, count(student_id) as student_count
2 from student
3 left outer join department ON
4 department.department_id=student.department_id
5 group by department_name
6 order by department_name;
#jaat
Use this query
select count(*) from tblstud_info s,tbldept d where s.dno=d.dno group by d.dname

Select maximum value from one column by second column

I have two tables:
EMPLOYEES
=====================================================
ID NAME SUPERVISOR LOCATION SALARY
-----------------------------------------------------
34 John AL 100000
17 Mike 34 NY 75000
5 Alan 34 LE 25000
10 Dave 5 NY 20000
BONUS
========================================
ID Bonus
----------------------------------------
17 5000
34 5000
10 2000
I have to write query which return a list of the highest paid employee in each location with their names, salary and salary+bonus. Ranking should be based on salary plus bonus. So I wrote this query:
select em.name as name, em.salary as salary, bo.bonus as bonus, max(em.salary+bo.bonus) as total
from employees as em
join bonus as bo on em.empid = bo.empid
group by em.location
But I'm getting wrong names and query don't return one employee without bonus (empid = 5 in employees table) which have highest salary based by location (25000 + 0 bonus).
You can either do
select
em.location,
em.name as name,
em.salary as salary,
IFNULL(bo.bonus,0)) as bonus,
max(em.salary+IFNULL(bo.bonus,0)) as total
from employees as em
left join bonus as bo on em.empid = bo.empid
group by em.location;
This query however relies on a group by behavior that is specific to MySQL and would fail in most other databases (and also in later versions of MySQL if the setting ONLY_FULL_GROUP_BY is enabled).
I would suggest a query like below instead:
select
em.location,
em.name as name,
em.salary as salary,
IFNULL(bo.bonus,0)) as bonus,
highest.total
from employees as em
left join bonus as bo on em.empid = bo.empid
join (
select
em.location,
max(em.salary+IFNULL(bo.bonus,0)) as total
from employees as em
left join bonus as bo on em.empid = bo.empid
group by em.location
) highest on em.LOCATION = highest.LOCATION and em.salary+IFNULL(bo.bonus,0) = highest.total;
Here you determine the highest salary+bonus for each location and use that result as a derived table in a join to filter out the employee with highest total for each location.
See this SQL Fiddle
Maybe try using a left join:
select em.name as name, em.salary as salary, bo.bonus as bonus, max(em.salary+bo.bonus) as total
from employees as em
left join bonus as bo on em.empid = bo.empid
group by em.location
It should be:
select
em.name as name,
em.salary as salary,
COALESCE(bo.bonus,0) as bonus,
max(em.salary + COALESCE(bo.bonus,0) ) as total
from employees as em
left join bonus as bo on em.empid = bo.empid
group by em.location
You can check it in SQLFiddle
Please try this:
select em.name as name, em.salary as salary,ISNULL(bo.bonus,0) as bonus,
max(em.salary+ISNULL(bo.bonus,0)) as total
from employees as em
left join bonus as bo on em.ID = bo.ID
group by em.name,em.salary, bo.bonus order by MAX(em.salary+ISNULL(bo.bonus,0)) Desc

Do I need a loop or is their an easier way here

I have a table called employees that contains the columns.
ID | Name | Salary | Department_id | Boss_id
So all employees are listed in this no matter where they're bosses or not. If someone is not a boss then their value for Boss_id will be NULL.
The aim is, to figure out if any employees earn more than their respective bosses and by respective I mean, from the same department.
I've been working on this trying to figure it out and I'm not sure if I need a loop to loop through all the departments or if there is an easier way.
No, you don't need a loop.
If you want to compare the salary of an employee to the salary of his "boss", you can use a JOIN operation.
To list only those employees that have a higher salary than their boss:
SELECT e.*
FROM employee e
JOIN employee b
ON b.id = e.boss_id
AND e.salary > b.salary
If you want to list all employees, and just add a column that indicates whether their salary is higher than their bosses salary, along with bosses salary:
SELECT e.*
, IF(e.salary>b.salary,'Y','N') AS higher_salary_than_boss
, b.salary AS boss_salary
FROM employee e
LEFT
JOIN employee b
ON b.id = e.boss_id
ORDER
BY e.id
I don't see how "department" really comes into play.
If you want to compare an employee's salary to of his bosses boss, you could add yet another LEFT JOIN to the employee table.
SELECT t1.ID, t1.Name
FROM table1 t1
INNER JOIN table2 t2
ON t1.ID = t2.Boss_id
AND t1.Salary > t2. Salary
AND t1.Department_id = t2.Department_id