I have a table named Employees with below two columns.
==================
Employees
1- EmpId (auto incremental id)
2- EmpName (varchar)
There is another table named 'LateDays' with below five columns.
==================
LateDays
1- LateDayId (auto incremental id)
2- EmployeeId (foreign key)
3- LateDate (DateTime)
4- FinePaid (bool)
5- Informed (bool)
Now I am trying to write a SQL statement to fetch employees along with their Total Fine, Paid Fine and their Allowed Quota Availed. Each employee has 4 allowed days to come late.
I came up with the following (incorrect) SQl, which works fine when there is only one employee in Employees table but fails for more.
SELECT
Employees.name as EmpName,
(select count(LateDays.LateDate)*200 from Employees inner join LateDays on Employees.EmpId = LateDays.EmployeeEmpId) as TotalFine,
count(LateDays.LateDate)*200 as PaidFine,
(select COUNT(LateDays.Informed)from Employees inner join LateDays on Employees.EmpId = LateDays.EmployeeEmpId where LateDays.Informed='true') as InformedDays
FROM
Employees inner join LateDays
on Employees.EmpId = LateDays.EmployeeEmpId
WHERE
LateDays.FinePaid = 1
GROUP BY
name
Kindly help me writing a proper SQL for my situation.
Edit:
I am trying to add sample data.
Employees table:
EmpId Name
1 Pervaiz
2 Nabeel
3 Muhammad
4 james
Late Days table:
LateDayId EmployeeEmpId LateDate FinePaid Informed
4 1 2014-09-21 0 0
5 1 2014-09-20 0 1
6 6 2014-09-21 0 0
7 6 2014-10-01 1 0
Best Answer
The reason this isn't working for you when you have multiple rows in the employee table is that it is not
correlated
back to the main query. By this I mean that SQL has no way of knowing which employee to count in your subqueries for a given row in your main query. You can avoid this buy adding a reference back to your main query like this:Notice how I aliased the tables in the subquery so they had a different name from those in the outer query. Then in the WHERE clause I referenced the table name from the outer query.
However this is not how I would write your query. It will probably be less than well performing. Instead you can use a pattern where you use a
CASE
statement to define your condition returning a 1 or a 0 thenSUM
the values.The final query looks like this:
A couple of things of note. I am checking that LateDate is not NULL in the first
SUM
to match yourCOUNT
.COUNT
doesn't actually count a value if it is NULL. Second is that I changed the GROUP by toEmployees.EmpId
. You generally do not want to GROUP BY aNAME
column. What happens when two employees have the same name? It's rare but it does happen. You are better off grouping on theID
column.EDIT: