This is the UML for the tables: https://dev.mysql.com/doc/employee/en/sakila-structure.html
This my attempt:
SELECT
CONCAT(employees.first_name, ' ', employees.last_name) AS 'EmployeeName',
salaries.emp_no AS 'Employee Number',
departments.dept_no AS 'Department Number',
departments.dept_name AS 'Department name',
AVG(salaries.salary) AS 'Average salary'
FROM salaries
INNER JOIN dept_emp
ON salaries.emp_no = dept_emp.emp_no
INNER JOIN employees
ON salaries.emp_no = employees.emp_no
INNER JOIN departments
ON dept_emp.dept_no = departments.dept_no
GROUP BY salaries.emp_no,
dept_emp.dept_no
I just get the average employee salary for all departments a person worked in. My desired result must group by each employee for each department. Any help is appreciated.
you can try this query
SELECT
CONCAT(employees.first_name, ' ', employees.last_name) AS 'EmployeeName',
salaries.emp_no AS 'Employee Number',
departments.dept_no AS 'Department Number',
departments.dept_name AS 'Department name',
Cte_DepartmentSalaries.AvgSalary AS 'Average Salary'
--AVG(salaries.salary) AS 'Average salary'
FROM salaries
INNER JOIN dept_emp
ON salaries.emp_no = dept_emp.emp_no
INNER JOIN employees
ON salaries.emp_no = employees.emp_no
INNER JOIN departments
ON dept_emp.dept_no = departments.dept_no
LEFT JOIN (SELECT
departments.dept_no,
departments.dept_name,
AVG(Salaries.Salary) AS AvgSalary
FROM Salaries
INNER JOIN dept_emp
ON salaries.emp_no = dept_emp.emp_no
INNER JOIN departments
ON dept_emp.dept_no = departments.dept_no
GROUP BY departments.dept_no,
departments.dept_name) AS Cte_DepartmentSalaries
ON dept_emp.dept_no = Cte_DepartmentSalaries.dept_no
if you join to salaries where to_date between from and to date you will get any changes in the salary over those time periods.
SELECT CONCAT(e.first_name,' ',e.last_name) AS 'EmployeeName',
s.emp_no AS 'Employee Number',
d.dept_no AS 'Department Number',
d.dept_name AS 'Department name',
AVG(s.salaries.salary) AS 'Average salary'
FROM employees e
JOIN dept_emp de ON e.emp_no = de.emp_no
JOIN salaries s ON s.emp_no = de.emp_no
AND (de.to_date >= s.from_date AND de.to_date <= s.to_date)
JOIN departments d ON d.dept_no = de.dept_no
GROUP BY s.emp_no,
d.dept_no
Change your group by to
GROUP BY employees.first_name, employees.last_name,
salaries.emp_no, departments.dept_no, departments.dept_name
mysql lets you (in a non helpful way IMHO) not put all columns used in the group by. Unlike other platforms that force you to put them all in if they are not in the aggregate function. So you are getting more than one of the same row, but you can't tell because mysql squishes them for you.
you probably also need this in your join
INNER JOIN dept_emp ON salaries.emp_no = dept_emp.emp_no
AND salaries.from_date = dept_emp.from_date
AND salaries.to_date = dept_emp.to_date
To find just the average salaries from a table use this mySQL query.
SELECT AVG(salary), COUNT(*)
FROM employees;MY
SELECT AVG(salary) FROM Employees GROUP BY(departments_id);
Looks like you would need to check for an overlap in the from_date
and to_date
, of the employee salary history ( salaries
table) and the employees department history ( dept_emp
table).
Assuming that a to_date
value of NULL represents "current", to find the overlap, the join would be something like this:
FROM salaries s
JOIN dept_emp de
ON ( de.emp_no = s.emp_no )
AND ( de.from_date <= s.to_date OR s.to_date IS NULL )
AND ( de.to_date >= s.from_date OR de.to_date IS NULL )
As far as getting the average salary, that's going to be a bit more complicated, depending on how you define "average".
As an example, if an employee worked in a department and the salary was 20,000 for one year, and then salary was 30,000 for four years... should the average salary be reported as 25,000 (the average of the two distinct values), or would it be 28,000 (total salary for all years, divided by the number of years.)
To get the latter result, we could use an expression that calculates the number of days the salary was effective for in the department...
TIMESTAMPDIFF(DAY
,GREATEST(de.from_date,s.from_date)
,LEAST(IFNULL(de.to_date,DATE(NOW())),IFNULL(s.to_date,DATE(NOW())))
)
We could multiple that by the effective salary, add all of those together, and then divide by the total number of days:
SUM(days*salary)/SUM(days)
An expression something like this:
SUM( TIMESTAMPDIFF(DAY
,GREATEST(de.from_date,s.from_date)
,LEAST(IFNULL(de.to_date,DATE(NOW())),IFNULL(s.to_date,DATE(NOW())))
)
*
s.salary
)
/
SUM( TIMESTAMPDIFF(DAY
,GREATEST(de.from_date,s.from_date)
,LEAST(IFNULL(de.to_date,DATE(NOW())),IFNULL(s.to_date,DATE(NOW())))
)
)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.