How to count rows in a table (phpMyAdmin) - php

I am currently working on an attendance system using php and mysql and I want to count the number of Present/Absent/Late of that student, which is happened on the same table. Like for example the table looks like this.
student_name | attendance status | date
| |
student1 | Present | 2019-02-21
student2 | Absent | 2019-02-21
student3 | Late | 2019-02-21
student1 | Absent | 2019-02-22
student2 | Absent | 2019-02-22
student3 | Present | 2019-02-22
I want output as below : Show how many presents/absents/late is a student in a month like
student 1 | 20 presents | 4 absents | 2 lates
I am using fpdf library but even a php code for that is a big help.
Table name : attendance_records
Solt'n
$result = mysqli_query($conn, "
SELECT student_name,
SUM(CASE WHEN attendance = 'Present' THEN 1 ELSE 0 END) AS presents,
SUM(CASE WHEN attendance = 'Absent' THEN 1 ELSE 0 END) AS absents,
SUM(CASE WHEN attendance = 'Late' THEN 1 ELSE 0 END) AS lates
FROM attendance_records
GROUP BY student_name
") or die("database error:". mysqli_error($conn));
foreach( $result as $row ) {
$pdf->SetFont('Arial','I',9);
$pdf->Ln();
foreach($row as $column) {
$pdf->Cell(39,10,$column,1);
}
}

You can combine SUM and CASE to achieve what you need
Try using query
SELECT student_name,
SUM(CASE WHEN attendance = 'Present' THEN 1 ELSE 0 END) AS presents,
SUM(CASE WHEN attendance = 'Absent' THEN 1 ELSE 0 END) AS absents,
SUM(CASE WHEN attendance = 'Late' THEN 1 ELSE 0 END) AS lates
FROM attendance_records
GROUP BY student_name

Use in phpmyadmin ..
SELECT * FROM table_name WHERE attendance_status = absent;
Phpmyadmin will count it automatically..
But you should code in php and mysql or mysqli ..

Related

SQL Statement to Group results by two rows to create a timetable

I currently have a database table which records the bookings of jobs
and there are 8 timeslots available
+-----------+
|tbl_booking|
+-----------+
|room_id |
|date |
|timeslot |
|booking |
+-----------+
sample data
+-----------+----------+-----------+
|room_id | date | timeslot |
+-----------+----------+-----------+
|1 |2018-01-01| 1 |
|1 |2018-01-01| 2 |
|1 |2018-01-01| 4 |
|2 |2018-01-01| 1 |
+-----------+----------+-----------+
intended outcome - when statement filters for bookings on 2018-01-01
+-----------+----------+-----------+----------+-----------+
|room |timeslot1 | timeslot2 |timeslot3 | timeslot4 |
+-----------+----------+-----------+----------+-----------+
|1 | X | X | | X |
|2 | X | | | |
+-----------+----------+-----------+----------+-----------+
i started off with this statement:
SELECT * from tbl_booking WHERE date = '2018-01-01' GROUP BY room_id
and this would return results to see the results grouped by rooms.
I would like to know where i should go from here to also have the results display it's timeslots that are shown in a table displaying the booking status of eacah room's timeslot in the day?
Should there be an SQL statement that i should be using or am I on the wrong track completely?
Any help would be appreciated.
Thank you!
What you want to do with the data isn't nice to do and if you have a fixed number of time slots then you can hardcode the columns like this:
SELECT room_id,
SUM(CASE WHEN timeslot = 1 then 1 else 0 END) AS Timeslot1,
SUM(CASE WHEN timeslot = 2 then 1 else 0 END) AS Timeslot2,
SUM(CASE WHEN timeslot = 3 then 1 else 0 END) AS Timeslot3,
SUM(CASE WHEN timeslot = 4 then 1 else 0 END) AS Timeslot4
FROM tbl_booking
GROUP BY room_id
(see SQL Fiddle)
You could use MAX if you just want to see if at least 1 booking exist
SQL to include remark, you can trick it to select the remark through a group by with MAX
SELECT room_id,
SUM(CASE WHEN timeslot = 1 then 1 else 0 END) AS Timeslot1,
MAX(CASE WHEN timeslot = 1 THEN remark ELSE '' END) AS Timeslot1Remark,
SUM(CASE WHEN timeslot = 2 then 1 else 0 END) AS Timeslot2,
MAX(CASE WHEN timeslot = 2 THEN remark ELSE '' END) AS Timeslot2Remark,
SUM(CASE WHEN timeslot = 3 then 1 else 0 END) AS Timeslot3,
MAX(CASE WHEN timeslot = 3 THEN remark ELSE '' END) AS Timeslot3Remark,
SUM(CASE WHEN timeslot = 4 then 1 else 0 END) AS Timeslot4,
MAX(CASE WHEN timeslot = 4 THEN remark ELSE '' END) AS Timeslot4Remark
FROM tbl_booking
GROUP BY room_id
your extended SQL Fiddle. This won't work for multiple dates only 1 selected date
If you are looking for dynamic solutions then you must need to use pivot table.
Select * from
(select * from yourtable) as
Temptable
Pivot (
Count(room)
For timeslot
In (list of timeslot))
As tempSlot
For more information check this link MySQL pivot table

Count data in every month

I've already research this in other question but I didn't get an answer so decide to ask here.
I have 2 tables which is the tblCourse and tblData, I have been storing all of my course list in tblCourse while in tblData I am storing the person name and what course they took. Now, what I want to do is, I want to get the total count of all the person who are taking a particular course in every month.
For example:
----------------------------------------------------------------------------
Course | Jan | feb | Mar | Apr | May | ......................| Dec | Total |
----------------------------------------------------------------------------
Course1 | 2 | 3 | 0 | 0 | 1 | ......................| 2 | 8 |
----------------------------------------------------------------------------
Course2 | 2 | 3 | 2 | 0 | 1 | ......................| 2 | 10 |
----------------------------------------------------------------------------
Course3 | 2 | 3 | 1 | 0 | 1 | ......................| 2 | 9 |
----------------------------------------------------------------------------
Here's my code:
<?php
$query = $this->db->query("SELECT * FROM tblcourse where category = 'Soft' and inex = 'inhouse' ORDER by course_name ASC");
foreach ($query->result() as $row){
?>
<tr>
<td>Id</td>
<td><?php echo $row->course_name; ?></td> // Output the Course Name
<td class="center"><?php echo $row->days; ?></td> //Output the Training days
<?php
$course = $row->course_name;
$query_jan = $this->db->query("SELECT * FROM tbldata where course like '%$course%' and course_end < '2016-11-30' and course_end >= '2016-11-01'");
?>
<td><?php echo $query_jan->num_rows(); ?></td> // Output the corresponding number of course taken by the person for the month of january
<? php
} // end of foreach
?>
Here's the structure of my database:
Table 1: tblCourse
Fields: ID, Course_name, Category, Training_days
Table 2: tblData
Fields: ID, Trainees_name, Course_taken, Date_start, Date_end
I'm just starting to develop using php.
Can I query this in a single query?
Considering Course_taken as foreign key to table tblCourse.
select tblCourse.Course_name,
Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec,(Jan+Feb+Mar+Apr+May+Jun+Jul+Aug+Sep+Oct+Nov+Dec) as `Total`
from (
select
tblCourse.Course_name+
sum(CASE WHEN month(tblData.Date_start)=1 or month(tblData.Date_end)=1 THEN 1 else 0 end) as `Jan`,
sum(CASE WHEN month(tblData.Date_start)=2 or month(tblData.Date_end)=2 THEN 1 else 0 end) as `Feb`,
sum(CASE WHEN month(tblData.Date_start)=3 or month(tblData.Date_end)=3 THEN 1 else 0 end) as `Mar`,
sum(CASE WHEN month(tblData.Date_start)=4 or month(tblData.Date_end)=4 THEN 1 else 0 end) as `Apr`,
sum(CASE WHEN month(tblData.Date_start)=5 or month(tblData.Date_end)=5 THEN 1 else 0 end) as `May`,
sum(CASE WHEN month(tblData.Date_start)=6 or month(tblData.Date_end)=6 THEN 1 else 0 end) as `Jun`,
sum(CASE WHEN month(tblData.Date_start)=7 or month(tblData.Date_end)=7 THEN 1 else 0 end) as `Jul`,
sum(CASE WHEN month(tblData.Date_start)=8 or month(tblData.Date_end)=8 THEN 1 else 0 end) as `Aug`,
sum(CASE WHEN month(tblData.Date_start)=9 or month(tblData.Date_end)=9 THEN 1 else 0 end) as `Sep`,
sum(CASE WHEN month(tblData.Date_start)=10 or month(tblData.Date_end)=10 THEN 1 else 0 end) as `Oct`,
sum(CASE WHEN month(tblData.Date_start)=11 or month(tblData.Date_end)=11 THEN 1 else 0 end) as `Nov`,
sum(CASE WHEN month(tblData.Date_start)=12 or month(tblData.Date_end)=12 THEN 1 else 0 end) as `Dec`
from tblCourse
left join tblData on tblCourse.id=tblData.Course_taken
group by tblCourse.id
) data
Note : Make sure Date_start and Date_end should be of same year.
SELECT COUNT(Trainees_name) FROM tbldata where Course_taken like '%$course%' and Date_start < '2016-11-30' and Date_end >= '2016-11-01'"

Separate Data into Days of the week mysql

Good day,
I am currently making a sales tracking report where the user pick a date range then the table should display the result.
for now I have this query that counts how many items are sold
select x_transaction_details.xitem,
SUM(x_transaction_details.qty) as totalNumberSold,
count(x_transaction_details.xitem) as occurence,
x_transaction_details.cost,
i_inventory.xitem,
x_transaction_details.date_at as transDate
from x_transaction_details
left join i_inventory on x_transaction_details.xitem = i_inventory.xid
where (x_transaction_details.date_at BETWEEN '2015-08-13 08:34:12' AND '2015-09-14 08:34:12')
GROUP BY x_transaction_details.xitem
ORDER BY occurence DESC
this query displays
|itemName| totalNumberSold | occurence | date
|item 1 | 23 pcs | 2 |
|item 2 | 18 pcs | 6 |
|item 3 | 203 pcs | 18 |
etc..
Now I want to know the breakdown of sales per day so I tried
select x_transaction_details.xitem,
SUM(x_transaction_details.qty) as sold,
count(x_transaction_details.xitem) as occurence,
x_transaction_details.cost,
i_inventory.xitem,
x_transaction_details.date_at as transDate
SUM(CASE WHEN date_at = DAYOFWEEK(1) THEN
count(x_transaction_details.xitem) END) as Sunday
from x_transaction_details
left join i_inventory on x_transaction_details.xitem = i_inventory.xid
where (x_transaction_details.date_at BETWEEN '2015-08-13 08:34:12' AND '2015-09-14 08:34:12')
GROUP BY x_transaction_details.xitem
ORDER BY occurence DESC
But its generating an error instead. I want to create a more detailed table
|itemName|Mon|Tue|Wed|Thur|Fri|Sat|Sun| totalNumberSold | occurence | date
|item 1 | 10| 0| 0 | 13 | 0 |0 |0 | 23 pcs | 2 |
|item 2 | 1 | 3| 12| 0 | 16|0 |0 | 32 pcs | 6 |
|item 3 | 0 | 6| 1 | 13 | 8 |7 |1 | 36 pcs | 12 |
etc..
Thanks for the tips, I can make this table using php (hard-way) too but I guess its doable using sql query as well. Have a good day ahead.
You are missing a comma and nesting aggregation functions. I think you want:
select i.xid, SUM(td.qty) as sold, count(td.xitem) as occurrence,
avg(td.cost) as avg_cost, i.xitem,
SUM(case when DAYOFWEEK(td.date_at) = 1 then td.qty else 0 end) as Sunday
from i_inventory i join
x_transaction_details td
on td.xitem = i.xid
where td.date_at BETWEEN '2015-08-13 08:34:12' AND '2015-09-14 08:34:12'
GROUP BY i.xid
ORDER BY occurrence DESC;
Notes:
"occurrence" has two r's.
Table aliases make the query easier to write and to read.
You can't nest aggregation functions.
You shouldn't include date_at in the select list because the value is not unique for each row.
The left join is either backwards (inventory should go first) or should be an inner join. In a properly formed database, you should not have items in the transaction table that are not in the inventory table (I don't think).
The actual code (might be helpful for anyone)
select x_transaction_details.xitem, count(x_transaction_details.xitem) as occurrence, i_inventory.xitem,
SUM(case when DAYOFWEEK(x_transaction_details.date_at) = 1 then x_transaction_details.qty else 0 end) as Sun,
SUM(case when DAYOFWEEK(x_transaction_details.date_at) = 2 then x_transaction_details.qty else 0 end) as Mom,
SUM(case when DAYOFWEEK(x_transaction_details.date_at) = 3 then x_transaction_details.qty else 0 end) as tue,
SUM(case when DAYOFWEEK(x_transaction_details.date_at) = 4 then x_transaction_details.qty else 0 end) as wed,
SUM(case when DAYOFWEEK(x_transaction_details.date_at) = 5 then x_transaction_details.qty else 0 end) as thur,
SUM(case when DAYOFWEEK(x_transaction_details.date_at) = 6 then x_transaction_details.qty else 0 end) as fri,
SUM(case when DAYOFWEEK(x_transaction_details.date_at) = 7 then x_transaction_details.qty else 0 end) as sat,
SUM(x_transaction_details.qty) as totalNumberSold
from x_transaction_details
left join i_inventory on x_transaction_details.xitem = i_inventory.xid
where (x_transaction_details.date_at BETWEEN '2015-08-13 08:34:12' AND '2015-09-14 08:34:12')
GROUP BY x_transaction_details.xitem
ORDER BY occurrence DESC
I did not used table aliases though :)

MySQL Group by column, then count by another column

I have a challenging MySQL problem that is beyond my basic knowledge, I would really appreciate any help.
I currently have the following query:
select users.userid, CAST(posts.time AS DATE)
FROM users INNER JOIN posts ON users.post_id = posts.id
Sample output:
userid | CAST(posts.time AS DATE)
1............2015-01-05
2............2015-02-06
2............2015-04-07
2............2015-04-07
3............2015-04-07
1............2015-02-06
7............2015-01-05
userid can repeat itself, there could be 10 different rows with userid = 1; same goes for the date column. I would like to count how many rows each userid had for each distinct date. Based on the above data, the output should be:
-----------------------1----------2--------3---------4--------5--------6-------7
2015-01-05.............1..........0........0.........0........0........0.......1
2015-02-06.............1..........1........0.........0........0........0.......0
2015-04-07.............0..........2........1.........0........0........0.......0
I have 7 users in total. I would like to further replace the user id with a name that I define; e.g. I would define 1 in the heading/title to be displayed as Mike, 2 to be displayed as George, and so forth...
Is it possible? Thanks everyone.
If you have 7 users only, and only ever will, pivoting the data is not too difficult:
select date(posts.time),
count(case when userid = 1 then userid end) as `1`,
count(case when userid = 2 then userid end) as `2`,
count(case when userid = 3 then userid end) as `3`,
count(case when userid = 4 then userid end) as `4`,
count(case when userid = 5 then userid end) as `5`,
count(case when userid = 6 then userid end) as `6`,
count(case when userid = 7 then userid end) as `7`
users INNER JOIN posts ON users.post_id = posts.id
group by date(posts.time)
demo here
If your number of users is variable, or prone to change - it becomes annoying and you'd be better off looking to your application language to take care of it.
Here's what I have (I didn't complete it for you):
SELECT date, SUM(id_1) AS Mike, SUM(id_2) AS George FROM (SELECT CASE id WHEN 1 THEN 1 ELSE 0 END as id_1, CASE id WHEN 2 THEN 1 ELSE 0 END as id_2, date FROM test_dates) as tmp GROUP BY date;
+------------+------+--------+
| date | Mike | George |
+------------+------+--------+
| 2015-01-05 | 1 | 0 |
| 2015-02-06 | 1 | 1 |
| 2015-04-07 | 0 | 2 |
+------------+------+--------+
The trick of substituting a summation of 1s when what you want is a count is a common reporting trick that is worth remembering. Blew my mind when I first saw it.

dynamic columns using pivot table query

I have this attendance table
---------------------------------------------------------------------------
attendance_id | stud_id | week | sy |sem |present
---------------------------------------------------------------------------
1 | 1 | 02/18/2012 | 2010-2011 |1st semester|1
2 | 2 | 02/18/2012 | 2010-2011 |1st semester|1
3 | 3 | 02/18/2012 | 2010-2011 |1st semester|1
4 | 1 | 02/25/2012 | 2010-2011 |1st semester|1
5 | 2 | 02/25/2012 | 2010-2011 |1st semester|1
6 | 1 | 03/03/2012 | 2010-2011 |1st semester|1
7 | 2 | 03/03/2012 | 2010-2011 |1st semester|1
8 | 3 | 03/03/2012 | 2010-2011 |1st semester|1
my query is this
Select cadet_record.fname,cadet_record.lname,cadet_record.mname, student_id,
MAX(case WHEN week = '02/18/2012' then present end) as 'week1',
MAX(case WHEN week = '02/25/2012' then present end) as 'week2'
From attendance
LEFT JOIN cadet_record ON cadet_record.stud_no = attendance.student_id WHERE section = '$section' AND schoolyear = '$year' AND component = '$component' AND semester = '$semester'
GROUP BY student_id
how can I dynamically call all the week without inserting the dates
for e.g. 02/28/2012, 02/29/2012 so on and so forth.
any ideas? =(
As far as I know, you can't dynamically add columns to a SELECT statement. What you're asking for is a way of presenting data and that is not something MySQL cares about. You should handle that in the front end.
However, you can cheat by creating your queries in your model and dynamically adding those new columns, by dynamically inserting more MAX(case... to the query string. That's not a nice solution, though.
Edit:
Im using php, how can I accomplish that?
So, I guess you're talking about the ugly solution. Well, basically you should dynamically create your query string (pseudocode):
$initialDay = 02/28/2012;
$lastDay = 03/28/2012;
$dayNumber = 1;
$sql = 'Select cadet_record.fname,cadet_record.lname,cadet_record.mname, student_id';
while ($initialDay <= $lastDay) {
$sql .= ', MAX(case WHEN week = $initialDay then present end) as day' . $dayNumber;
$initialDay = $initialDay + 1 day;
$dayNumber++;
}
$sql .= ' From attendance blah blah...';
Then your query should look like this for dates from 02/18/2012 to 03/18/2012:
Select cadet_record.fname,cadet_record.lname,cadet_record.mname, student_id,
,MAX(case WHEN week = '02/18/2012' then present end) as day1
,MAX(case WHEN week = '02/19/2012' then present end) as day2
From attendance
LEFT JOIN cadet_record ON cadet_record.stud_no = attendance.student_id WHERE section = '$section' AND schoolyear = '$year' AND component = '$component' AND semester = '$semester'
GROUP BY student_id
Notice I added days instead of weeks because your example showed increasing days, although the column name was weeks
Without pivoting the table, you can get the weekly attendance of each student with this query:
SELECT
cadet_record.fname,
cadet_record.lname,
cadet_record.mname,
student_id,
week,
SUM(present) AS att
FROM attendance
LEFT JOIN cadet_record
ON cadet_record.stud_no = attendance.student_id
WHERE section = '$section'
AND schoolyear = '$year'
AND component = '$component'
AND semester = '$semester'
GROUP BY week, student_id
ORDER BY week, cadet_record.fname, student_id
(EDIT Sorry, you should use SUM, not COUNT).

Categories