Restrict rows based on a join table, using a count - sql

I have a employee table, and a vacations table where each row represents a day they took for vacation.
I want to get all employees who have taken more vacation days that their maximum vacation days value.
employees:
employeeId
maxVacationDays
vacations:
employeeId
date_vacation_day_taken
Query I have now:
SELECT e.*
FROM employees e
INNER JOIN vacations v ON (v.employeeId = e.employeeId)
WHERE e.isActive = true AND ( ???? > e.maxVacationDays)
So I need to get the count of rows from the vacations table for that employeeId.
Do I need a subquery for this?
(using sql2000)

Try this:
SELECT e.employeeId, v.maxVacationDays
FROM employees e
INNER JOIN vacations v ON (v.employeeId = e.employeeId)
WHERE e.isActive = true
GROUP BY e.employeeId, v.maxVacationDays
HAVING COUNT(v.employeeId) > v.maxVacationDays

Try this:
SELECT * FROM
(
SELECT e.employeeId, e.maxVacationDays,
SUM(v.date_vacation_day_taken) 'dayscount'
FROM employees e
INNER JOIN vacations v ON (v.employeeId = e.employeeId)
GROUP BY e.employeeId, e.maxVacationDays
WHERE e.isactive = true
) sub
WHERE sub.dayscount > e.maxVacationDays)

Maybe this:
select e.employeeId, e.maxVacationDays, count(v.*) as vacationDaysTaken
from employees e
join vacations v on e.employeeId = v.employeeId
group by e.employeeId, e.maxVacationDays
having e.maxVacationDays < count(v.*)

SELECT e.EmployeeId
,COUNT(v.date_vacation_day_taken) TotalDaysTaken
,e.maxVacationDays MaxDaysAllowed
FROM Employees e
INNER JOIN vacations v
ON v.employeeId = e.employeeId
WHERE e.isactive = true
GROUP BY e.EmployeeId, e.maxVacationDays, e.isactive
HAVING COUNT(v.date_vacation_day_taken) > e.maxVacationDays

Related

Select value from 2 tables with condition

I want to select values Employee ID, employee first name, project name from tables employee and project of the employee assigned to more than one project.
Thanks everybody I can solve them and sorry about this question is not clear
You must use a JOIN
select EmplyoeeID, FirstName, ProjectName
from EmployeeDetail
join ProjectDetail on EmplyoeeDetailID = EmployeeID
where (select count(*) from ProjectDetail where EmplyoeeDetailID = EmployeeID) > 1
Please read more about joins here: https://www.w3schools.com/sql/sql_join.asp
Try this (a simple INNER JOIN)
SELECT e.EmployeeID, e.firstName, p.ProjectName
FROM Employee e
JOIN ProjectDetail p
ON e.EmployeeID = p.EmployeeDetailID
If you want only employees with more than 1 project
SELECT e.EmployeeID, e.firstName, p.ProjectName
FROM Employee e
JOIN ProjectDetail p
ON e.EmployeeID = p.EmployeeDetailID
WHERE
(SELECT COUNT(1) FROM ProjectDetail p2
WHERE p2.EmployeeDetailID = p.EmployeeDetailID) > 1
A window function is probably the most efficient
SELECT
e.EmployeeID,
e.firstName,
p.ProjectName
FROM Employee e
JOIN (
SELECT p.*,
count = COUNT(*) OVER (PARTITION BY p.EmployeeDetailID)
FROM ProjectDetail p
) p ON e.EmployeeID = p.EmployeeDetailID AND p.count > 1;

Which employee has processed most orders?

I was trying to do my exercise to get an answer to this question,
--Which employee has processed most orders?
following the table below;
and in SQL the query became this monster
select e.employeeid, e.lastname, count(*) as 'aantal' from employee e
join orders o on e.EmployeeID = o.EmployeeID group by e.EmployeeID,
e.LastName having count(*) = (
select top 1 count(*) as 'aantal' from employee e
join orders o on e.EmployeeID = o.EmployeeID
group by e.FirstName
order by count(*) desc
)
my question is, is there really no other ways to get an answer from this:
select e.employeeid, e.lastname, count(*) as 'aantal' from employee
join orders o on e.EmployeeID = o.EmployeeID
group by e.EmployeeID, e.LastName
and then just find a maximum of these table??
like: max(and here query)
You probably can try this:
select e.employee_id, e.title, count(o.order_id) as c from orders o join employees e on e.employee_id = o.employee_id group by e.employee_id, e.title order by c desc;
Answer to my question.
This is just impossible in SQL
https://www.youtube.com/watch?v=8hyCpyhj8Jc&ab_channel=DaveSullivan

How to get the average score of a department using sql

I want to get the average score of all department in my database, I have a query that get the average score of just one department, is there a way I can get the name of the department and their average score.
Lets assume I have 2 departments(Server and IT), The average of the server is the sum of all score of the people in that department divided by the total number of the department.
Here is a query I Have, but it's just the average of one department
SELECT SUM(RatingId)/(select COUNT(Id) from Employee where DepartmentId = 5) as Sums
FROM PerformanceReviewRatings pfr join
Employee e
on pfr.EmployeeId = e.Id join
Department d
on d.Id = e.DepartmentId
WHERE pfr.AppraisalId = 1009;
Use group by
SELECT e.DepartmentId, d.name,
SUM(RatingId)/COUNT(1) as Sums
FROM PerformanceReviewRatings pfr
JOIN Employee e
ON pfr.EmployeeId = e.Id
JOIN Department d
ON d.Id = e.DepartmentId
WHERE pfr.AppraisalId = 1009
GROUP BY e.DepartmentId, d.name
Assuming an employee gets only one rating, you don't need a subquery or a reference to the Department table:
SELECT e.DepartmentId,
SUM(RatingId)/COUNT(*) as average_rating
FROM Employee e LEFT JOIN
PerformanceReviewRatings pfr
ON pfr.EmployeeId = e.Id AND
pfr.AppraisalId = 1009
GROUP BY e.DepartmentId;
If you only want the average of employees with ratings -- rather than one your question asks (which is to treat unrated employees as 0s -- then:
SELECT e.DepartmentId, AVG(RatingId) as average_rating
FROM Employee e JOIN
PerformanceReviewRatings pfr
ON pfr.EmployeeId = e.Id
WHERE pfr.AppraisalId = 1009
GROUP BY e.DepartmentId
Using the AVG() function.
SELECT e.DepartmentId,
AVG(RatingId) as average_rating
FROM Employee e LEFT JOIN
PerformanceReviewRatings pfr
ON pfr.EmployeeId = e.Id AND
pfr.AppraisalId = 1009
GROUP BY e.DepartmentId

--- SQL QUERY --- Which employees are older than their manager?

I have a table named employee. It includes managers and employees. There is also birthdate column and i need to find "older employees than THEIR managers". How can I do it? Could you give me some clue?
You could use an inner join to the same table:
select e.*
from employees e
inner join employees m
on e.managerid = m.id
and e.birthdate < m.birthdate
or exists() in the where:
select e.*
from employees e
where exists (
select 1
from employees m
where e.managerid = m.id
and e.birthdate < m.birthdate
)
If your employees structure is something like:
id,
name,
birthdate,
manager_id
This could be a solution:
select id, name
from employees e
where
exists
(select *
from employees m
where
m.id = e.manager_id and
m.birthdate > e.birthdate);

SQL Server 2005 - Nested recursive query :(

I have a query that I need to execute that I do not know how to structure.
I have a table called Employees. I have another table called Company. There is a third table called Files. As you can imagine, a Company has Employees, and Employees have Files.
I need to list out all of the Employees in my database. The challenge is, I need to list the total number of Files in the same company as the Employee. I have tried variations on the following without any luck:
SELECT
e.FirstName,
e.LastName,
e.Company,
(SELECT COUNT(*) FROM Files f WHERE f.EmployeeID IN (SELECT [ID] FROM Employees e2 WHERE e2.CompanyID=e.CompanyID)) as 'FileCount'
FROM
Employees e
What am I doing wrong? Thank you!
Try this:
SELECT
e.FirstName,
e.LastName,
e.Company,
(
SELECT COUNT(*)
FROM Files f
JOIN Employees e2 ON f.EmployeeID = e2.id
WHERE e2.CompanyID = e.CompanyID
) as 'FileCount'
FROM
Employees e
There are a lot of ways to get that. If the performance is a concern, this is more optimal according to estimated execution plan costs.
SELECT
e.FirstName,
e.LastName,
e.Company,
COUNT(f.FileId)
FROM
Employees e
INNER JOIN Files f ON e.EmployeeID = f.EmployeeID
GROUP BY
e.FirstName,
e.LastName,
e.Company
A solution with no correlation in SELECT clause. Probably quicker...
SELECT
e.FirstName,
e.LastName,
e.Company,
foo.FileCount
FROM
Employees e
JOIN
(
SELECT
COUNT(*) AS FileCount, --OR COUNT(DISTINCT something) ?
e2.Company, f.EmployeeID
FROM
Files f JOIN Employees e2 ON f.EmployeeID = e2.id
GROUP BY
e2.Company, f.EmployeeID
) foo ON e.Company = foo.Company AND e.id = foo.EmployeeID
How about:
SELECT
e.FirstName,
e.LastName,
e.Company,
select count(*) from Files f, Employees e where f.EmployeeID=e.EmployeeID and e.CompanyID=emp.CompanyID
FROM
Employees emp
WITH FilesPerCompany (CompanyID, NumberOfFiles)
AS (SELECT c.ID AS CompanyID,
COUNT(*) AS NumberOfFiles
FROM Companies c
INNER JOIN Employees e ON c.ID = e.CompanyID
INNER JOIN Files f ON e.ID = f.EmployeeID
GROUP BY c.ID
)
SELECT e.FirstName,
e.LastName,
e.Company,
COALESCE(s.NumberOfFiles, 0) AS NumberOfFilesPerCompany
FROM Employees e
LEFT JOIN FilesPerCompany s
ON s.CompanyID = e.CompanyID
The following statement uses recursive joins to iterate down employees who manage other employees who manage other employees .... etc. Our structure is a little convoluted as the management structure is role based which actually allows an employee to have more than 1 manager. You can add a reference to Files within this recursion.
WITH Manager as
(SELECT c.Forenames + ' ' + c.Surname as Employee,
c2.Forenames + ' ' + c2.Surname AS Manages,
c.accountid AS AccountID, c.[Status] AS [Status]
FROM [intranet].[dbo].[tblContact] c
LEFT JOIN tblContactPost cp ON cp.contactid = c.contactid
LEFT JOIN tblPost p ON p.ParentRoleId = cp.RoleID AND p.ParentPostArea = cp.PostArea AND p.ParentPostNo = cp.PostNo
INNER JOIN tblContactPost cp2 ON cp2.RoleId = p.RoleId AND cp2.PostArea = p.PostArea AND cp2.PostNo = p.PostNo
INNER JOIN tblContact c2 ON c2.ContactID = cp2.ContactId
)
,jn AS
(SELECT Employee, Manages
FROM Manager
Where AccountID = 'ad\lgardner' AND [Status] = 'A'
UNION ALL
SELECT c.Employee, c.Manages
FROM jn as p JOIN Manager AS c
ON c.Employee = p.Manages
)
SELECT jn.Employee, jn.Manages
From jn
Order BY 1