using where in count sql - sql

I have this SQL which works fine
SELECT COUNT(*) AS total, e.FirstName, e.LastName
FROM [Messages] AS m
INNER JOIN Employees AS e ON m.SenderId = e.UserId
GROUP BY e.EmployeeId, e.FirstName, e.LastName
But I want to also have total unread messages as column.
How can I achieve this in SQL?
SELECT
COUNT(*) AS total,
COUNT(where m.isRead = false) AS totalUnreadMessages,
e.FirstName, e.LastName
FROM
[Messages] AS m
INNER JOIN
Employees AS e ON m.SenderId = e.UserId
GROUP BY
e.EmployeeId, e.FirstName, e.LastName

You are almost there, use a case expression to do conditional counting:
SELECT Count(*) as total,Count(case when m.isRead = false then 1 end) as totalUnreadMessage,
e.FirstName,e.LastName
FROM [Messages] as m
inner join Employees as e on m.SenderId=e.UserId
group by e.EmployeeId, e.FirstName,e.LastName

I would write this as:
SELECT e.FirstName, e.LastName, COUNT(*) as total,
SUM(CASE WHEN m.isRead = 0 THEN 1 ELSE 0 END) as total_unread
FROM [Messages] m JOIN
Employees e
ON m.SenderId = e.UserId
GROUP BY e.EmployeeId, e.FirstName, e.LastName;

You can count them then join them with the original select:
SELECT Count(*) as total,tbNotRead.NotReadNumber AS totalUnreadMessage, e.FirstName,e.LastName
FROM [Messages] as m
INNER JOIN Employees as e ON m.SenderId=e.UserId
LEFT OUTER JOIN
(
SELECT m.Sender, COUNT(*) NotReadNumber
FROM [Messages] msgs
WHERE m.isRead = FALSE
GROUP BY m.Sender
)tbNotRead
ON tbNotRear.Sender = m.sender
GROUP BY e.EmployeeId, e.FirstName,e.LastName, tbNotRead.NotReadNumber

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

What would be the result of the following query?

The following query I tried...
select d.deptID, max(tt.total)
from dept d,
(select d.deptID, d.deptName, sum(days) as total
from vacation v, employee e, dept d
where v.empId = e.empID
and d.deptID = e.deptID
group by d.deptID, d.deptName) tt
where d.deptID = tt.deptID
group by d.deptName;
--having max(tt.total);
Try using limit since your inner query already does the calculation.
select TOP 1 * from (
select d.deptID, d.deptName, sum(days) as total
from vacation v, employee e, dept d
where v.empId = e.empID
and d.deptID = e.deptID
group by d.deptID, d.deptName)
order by total desc;
Depends on the dbms you're using.. this is for mysql
In oracle use where rownum = 1
In sql server use SELECT TOP 1 *
Using Top:
Select top 1 with ties * from
(Select D.DepartmentName, sum(V.Days) as SumDays
from Vacations V
inner join Employee E on E.EmployeeID=V.EmployeeID
inner join Department D on D.DepartmentID=E.DepartmentID
group by D.DepartmentName)SumDays
Order by SumDays desc
Try like this,
SELECT TOP 1 d.departmentname,
Sum(v.days) AS vacations
FROM employee emp
INNER JOIN department d
ON d.departmentid = emp.departmentid
INNER JOIN vacations v
ON v.employeeid = emp.employeeid
GROUP BY d.departmentname
ORDER BY 2 DESC

Restrict rows based on a join table, using a count

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

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