I'm using MySQL 5.1 and I have two tables, projects and employee. There is a foreign key in employee (number_project) that is the primary key of projects(code_project).
---> Exactly: SQL Fiddle
I'm trying get the SUM of the projects by department with this query:
SELECT emp.department_emp AS Department, SUM( pro.price ) AS total_department
FROM employee AS emp, projects AS pro
WHERE emp.number_project = pro.code_project
GROUP BY emp.department_emp
It returns:
DEPARTMENT TOTAL_DEPARTMENTA
Accounting 2600
IT 4200
But It should returns:
DEPARTMENT TOTAL_DEPARTMENT
Accounting 1300
IT 4200
The problem is that when the query sums the same projects many times as employees of the same department are working in that project.
Thanks!
Use a subquery to create a list of unique (department, project) combinations:
select e.department_emp
, sum(p.price)
from (
select distinct department_emp
, number_project
from Employee
) e
join Projects p
on p.code_project = e.number_project
group by
e.department_emp
Working example at SQL Fiddle.
Your database could use some serious work. Employee to project should be a many-to-many relation, not a many-to-one relation. And a field called "number" should not be called "code" in another table.
You can use a subquery that "collapses" the employees, arbitrarily choosing the department of one employee from the project:
SELECT department,
SUM(price) AS total_department
FROM ( SELECT project.code_project AS project,
project.price AS price,
MIN(employee.department_emp) AS department
FROM project
JOIN employee
ON project.code_project = employee.number_project
GROUP
BY project.code_project,
project.price
)
GROUP
BY department
;
(Naturally, this will give misleading results if a single project has employees from multiple different departments, because it will assign the entire price of the project to one of those departments.)
SELECT emp.department_emp AS Department, SUM( pro.price ) AS total_department
FROM(SELECT DISTINCT *
FROM employee AS emp, projects AS pro
WHERE emp.number_project = pro.code_project
) AS P
GROUP BY emp.department_emp
Related
I have two tables, one is departments and the other is employees. The department id is a foreign key in the employees table. The employee table has a name and a flag saying if the person is part-time. I can have zero or more employees in a department. I'm trying to figure out out to get a list of all departments where a department has at least one employee and if it does have at least one employee, that all the employees are part time. I think this has to be some kind of subquery to get this. Here's what I have so far:
SELECT dept.name
,dept.id
,employee.deptid
,count(employee.is_parttime)
FROM employee
,dept
WHERE dept.id = employee.deptid
AND employee.is_parttime = 1
GROUP BY employee.is_parttime
I would really appreciate any help at this point.
You must join (properly) the tables and group by department with a condition in the HAVING clause:
select d.name, d.id, count(e.id) total
from dept d inner join employee e
on d.id = e.deptid
group by d.name, d.id
having total = sum(e.is_parttime)
The inner join returns only departments with at least 1 employee.
The column is_parttime (I guess) is a flag with values 0 or 1 so by summing it the result is the number of employees that are part time in the department and this number is compared to the total number of employees of the department.
As a preliminary aside, I recommend expressing joins with the JOIN keyword, and segregating join conditions from filter conditions. Doing so would make the original query look like so:
select dept.name, dept.id, employee.deptid, count(employee.is_parttime)
from employee
join dept on dept.id = employee.deptid
where employee.is_parttime = 1
group by employee.is_parttime
It doesn't make much practical difference for inner joins, but it does make the structure of the data and the logic of the query a bit clearer. On the other hand, it does make a difference for outer joins, and there is value in consistency.
As for the actual question, yes, one can rewrite the original query using a subquery or an inline view to produce the requested result. (An "inline view" is technically what one should call an embedded query used as a table in the FROM clause, but some people lump these in with subqueries.)
Example using a subquery
select dept.name, dept.id
from dept
where dept.id in (
select deptid
from employee
group by deptid
having count(*) == sum(is_parttime)
)
Example using an inline view
select dept.name, dept.id
from dept
join (
select deptid
from employee
group by deptid
having count(*) == sum(is_parttime)
) pt_dept
on dept.id = pt_dept.deptid
In each case, the subquery / inline view does most of the work. It aggregates employees by department, then filters the groups (HAVING clause) to select only those in which the part-time employee count is the same as the total count. Naturally, departments without any employees will not be represented. If a list of department IDs would suffice for a list of departments, then that's actually all you need. To get the department names too, however, you need to combine that with data from the dept table, as demonstrated in the two example queries.
In my code I am trying to combine two data tables, Employee and Department. I tried to write a query to print the respective Department Name and number of employees for all departments, even the unstaffed ones. My query looks like this:
SELECT department.name, count(department.name) AS CountOfNAME
FROM department LEFT JOIN employee ON department.dept_id = employee.dept_id
GROUP BY department.name
ORDER BY Count(department.name) DESC, department.name ASC;
And the result is:
Engineering 5
Recruitment 5
Sales 3
Product 2
Finance 1
Operations 1
Research&Development 1
This code works in that it orders departments by number of employees, and then alphabetically, but Finance and Research&Development are not supposed to have any people in them. Is there any way to correctly display those results as having 0 employees? It seems to be a hard thing to do in SQL because of how join works.
The COUNT function should ignore NULL values, giving you a zero count for the finance and research departments. The problem is that you are counting a column in the department table, which always will be non NULL due to that this table is on the left side of the LEFT JOIN. Instead, try counting a column in the employee table:
SELECT department.name,
COUNT(employee.dept_id) AS CountOfNAME
FROM department
LEFT JOIN employee
ON department.dept_id = employee.dept_id
GROUP BY department.name
ORDER BY COUNT(employee.dept_id) DESC,
department.name ASC;
I suggest you create a view for the tallies of employees by department e.g.
CREATE VIEW DepartmentEmployeeTallies
AS
SELECT dept_id, COUNT(*) AS tally
FROM employee
UNION
SELECT dept_id, 0 AS tally
FROM department
WHERE dept_id NOT IN ( SELECT dept_id FROM employee );
Then things resolve to a simple join:
SELECT name, tally
FROM department
NATURAL JOIN
DepartmentEmployeeTallies;
Question:
Get the first and last names of all employees who entered the project at the same time as at least one other employee.
I have four tables Employee, Department, Project, Works_on as shown in below.
I tried the query:
SELECT
emp_fname,
emp_lname
FROM employee a,
works_on b
WHERE a.empno=b.empno;
Please let me know what is wrong with what I am doing?
for this you need to use both Employee (emp_no,emp_fname,emp_lname) and Works_on (emp_no, Enter_date) relationship linked through emp_no on both tables.
in your query you just used Employee table which does not have connection with checking project submitted times.
You can use either of the below query to get the desired results. I have used partition by clause to group related data.
WITH QUERY1 AS (
SELECT EMP_NO,ENTER_DATE, COUNT(*) OVER (PARTITION BY ENTER_DATE ORDER BY EMP_NO ) "t" FROM works_on)
select t2.emp_fname, t2.emp_lname from query1 t1 inner join employee t2 on t1.emp_no=t2.emp_no where "t">1;
select emp_fname, emp_lname from employee where emp_no in (
SELECT EMP_NO FROM (
SELECT EMP_NO,ENTER_DATE, COUNT(*) OVER (PARTITION BY ENTER_DATE ORDER BY EMP_NO ) "t" FROM works_on
) query1 where query1."t">1);
First of all your query will return employee names who ever worked on any project, and better you would use INNER JOIN.
If I understand right; you want employee who work on the same project (let's say ProjectX) and again the employee who entered ProjectX on same time and also there must be at least 2 employee having the same time on ProjectX.
If I am correct with the above:
You need to group your data. For instance first group projects that have at least 2 same enter_date like
SELECT Project_no, Enter_date FROM Works_on having Count(emp_no)>=2
This will give you all projects and dates that have employee more or equal than 2. Now we can find employee that worked on these projects at these dates.
SELECT emp_fname, emp_lname FROM Employee INNER JOIN Works_on AS WO ON WO.emp_no=Employee.emp_no
INNER JOIN
(
SELECT Project_no, Enter_date FROM Works_on having Count(emp_no)>=2
) AS PWith2MoreEmployee
ON PWith2MoreEmployee.Project_no=WO.Project_no
AND
PWith2MoreEmployee.Enter_date=WO.Enter_date
I hope this will give you what you are looking for.
I'm finding it a bit confusing to solve the following questions...
"
An employee may be assigned to more than one project and a project may have many employees. Consider the following relational schema and write SQL statements for the below queries.
Employees (empID, empName, empDOB, empAddress, salary, deptID, jobID)
Assignments (empID, projID, assignedDate, completionDate, status)`
Projects (projID, projDescription, startDate, endDate, projType)
(a) Display the names of employees who were born before 31st Jan 1980 and assigned a ‘Office Complex’ type project, sort results in ascending order of name.
(b) Retrieve the empIDs who are assigned at least two (2) projects.
"
My answer so far .
(a) SELECT empName FROM EMPLOYEES WHERE empDOB < '31-january-1980' AND ....
"
Please help me out
try this :
A)
SELECT employee.empName
FROM Assignments ass
JOIN Employees employee
ON employee .empID= ass.empID
JOIN Projects project
ON project.projID= ass .projID
WHERE employee.empDOB < '31-january-1980'
AND project.projType = ‘Office Complex’
ORDER BY employee.empName;
Without using JOIN CLAUSE
SELECT DISTINCT employee.empName
FROM Employees employee
WHERE employee.empDOB < '31-january-1980'
AND employee.empID IN (
SELECT ass.empID
FROM Assignments ass
WHERE ass.projID IN (
SELECT project.projID
FROM Projects project
WHERE project.projType = ‘Office Complex’
)
)
ORDER BY employee.empName ASC;
b)
SELECT ass.empID, COUNT(*) as counting
FROM Assignments ass
GROUP BY ass.empID
HAVING COUNT(*) >= 2;
So I want to make a query that shows the managers name who have employees with less than two orders. I have two queries:
This one shows employees who have less than two orders
Select Employee.EID
FROM Employee, OrderT
WHERE Employee.EID = OrderT.EID
GROUP BY Employee.EID
HAVING COUNT(OrderID) < 2
This one shows the manager of each employee
SELECT Employee.Name AS Manager
FROM Employee, Employee M
WHERE Employee.EID = M.ManagerID
GROUP BY Employee.Name
I am trying to combine them and make a subquery but for the life of me I can't figure it out. I keep trying different things for the past two hours and can't seem to get it. Any ideas?
Just need to add manager id to first query since the manager field is in the employee table.
Select Employee.EID, Employee.ManagerID
FROM Employee, OrderT
WHERE Employee.EID = OrderT.EID
GROUP BY Employee.EID
HAVING COUNT(OrderID) < 2