php - Finding the total in a column - php

I have a log` that saves log records (amount earned, etc) of employees and a code that separates the data into tables grouped under each employee id:
Empid: 0001
---------------------------
| Logid | Hours | Pay |
---------------------------
| 1001 | 10 | 50 |
---------------------------
| 1002 | 2 | 10 |
---------------------------
Empid: 0003
---------------------------
| Logid | Hours | Pay |
---------------------------
| 1003 | 3 | 9 |
---------------------------
| 1004 | 6 | 18 |
---------------------------
I managed this with the following semi-pseudocode:
$query = mysql_query("SELECT * FROM `log` ORDER BY empid");
$id = 0;
while ($list = mysql_fetch_assoc($query)) {
if ($id != $list['logid']) {
create header (Logid, Hours, Pay)
$id = $list['logid'];
}
add each data row for the empid
}
But now I would like to add the total of the Pay column and put it at the bottom of each table for each empid.
By putting the code $total_pay = $total_pay + $list['pay'] in the while loop I can get the total pay but I can't figure out how I might be able to show the total at the bottom.
Would really appreciate any advice on this!

This should do it. You basically sum up until the id is changing.
$sum = 0;
while ($list = mysql_fetch_assoc($query)) {
if ($id != $list['logid']) {
//create the totals using $sum !!!
// after that re-set sum to 0
$sum = 0;
//create header (Logid, Hours, Pay)
$id = $list['logid'];
}
$sum += $list['Pay'];
//add each data row for the empid
}
Also...
Please, don't use mysql_* functions in new code. They are no longer maintained and are officially deprecated. See the red box? Learn about prepared statements instead, and use PDO, or MySQLi - this article will help you decide which. If you choose PDO, here is a good tutorial.

There are two ways that you can do this.
PHP
Keep a running total of all of the "pay" values, and add it into your table at the bottom. For example:
$i=0;
while ($list = mysql_fetch_assoc($query)) { // for each row in your results
if ($id != $list['EmployeeId']) { // We only enter this loop if the EmployeeId doesn't equal $id. This can happen because either $id doesn't exist yet, or it doesn't match the previous EmployeeId
$i++; // increase $i by 1
if($i>1) { // Enter this loop only if $i is greater than or equal to 2 (if it is less than two, then this is our first time running this script, and adding a footer row wouldn't make any sense).
create footer (EmployeeId, Hours, Pay); // Log Id is irrelevant here
}
// reset your variables here
$id = $list['EmployeeId']; // set $id = the first or the new Employee ID
$total_pay = $list['pay']; // This is our first time for this Employee, so don't just add it to the running total
create header (EmployeeId, Hours, Pay) // Create the top half of your table
} else { // The EmployeeId has been established: we only need to change the running total
$total_pay = $total_pay + $list['pay'];
}
// add a data row for each LogId. This executes every time we go through the loop
create_normal_row(LogId, EmployeeId, Hours, Pay)
}
// At this point, both Employees have a header, and all data rows. However, we left the loop before we could add the last Employee's footer row
// Let's add one more footer row for the last user
create_footer (Logid, Hours, Pay);
SQL
MySQL has a function that does something very similar to what you are trying to do called ROLLUP. You can read more about it here:
http://dev.mysql.com/doc/refman/5.0/en/group-by-modifiers.html
Basically, you would change your query to work like this:
SELECT LogId, EmployeeId, SUM(Hours), SUM(Pay) FROM `log`
GROUP BY empid, logid WITH ROLLUP
This query will return a dataset that looks like this:
---------------------------------------
| Logid | EmployeeId| Hours | Pay |
---------------------------------------
| 1001 | 1 | 10 | 50 |
---------------------------------------
| 1002 | 1 | 2 | 10 |
---------------------------------------
| NULL | 1 | 12 | 60 |
---------------------------------------
| 1003 | 2 | 3 | 9 |
---------------------------------------
| 1004 | 2 | 6 | 18 |
---------------------------------------
| NULL | 2 | 9 | 27 |
---------------------------------------
| NULL | NULL | 21 | 87 |
---------------------------------------
Whenever $list['Logid'] is null, you know that you have a "total" row. Be careful though, this will add a "sum of all employees" row at the bottom of your dataset. If $list['EmployeeId'] is null, then you know you're in this "total" row.
On a related note (I'm not sure if this is what you're asking for), you can show this stuff in a table by using HTML <table> elements.
Each row would look like this:
<table> <!-- shown at the beginning of each table -->
<tr> <!-- shown at the beginning of each row -->
<td> <!-- shown at the beginning of each table cell -->
Your text goes here
</td> <!-- shown at the end of each table cell -->
<td>
More text can go here
</td>
</tr> <!-- shown at the end of each row -->
</table> <!-- shown at the end of each table -->
<tr>s can be repeated indefinitely within each <table>, and <td>s can be repeated within <tr>s.

Related

SQL query returns one row too few

SOLUTION: Make sure you don't 'use up' any $responses->fetch_assoc()s before the while loop.
I performed mysqli_fetch_array($responses);.
In php I have this sql query (simplified for your convenience, but the problem remains)
$sql = "SELECT id, content FROM responses ORDER BY RAND()";
$responses = $conn->query($sql);
where the responses table looks like this:
+----+----------+--------+------+
| id | content | userId | part |
+----+----------+--------+------+
| 4 | peewee | 31 | 1 |
| 5 | tallinn | 31 | 1 |
| 6 | dewey | 31 | 1 |
| 7 | stanford | 31 | 1 |
+----+----------+--------+------+
That doesn't format properly so all you need to know is that the id and content rows are different for each entry while the rest is the same for each.
The problem is, when I do a while loop on $responses like so:
while ($row = $responses->fetch_assoc()) {
$responseId = $row["id"];
$content = $row["content"];
echo " id: ".$responseId;
echo " content: ".$content;
}
I always get 1 record fewer than there are. In this case, since there are 4 rows, I would only see 3 echoed. However, it is not always the same 3, nor are they in the same order. If I remove the ORDER BY RAND() clause, then it is always the first record which is left out.
Thanks in advance
Cheers

Display some data from row and column

I'm trying to display first and second result from table, so that user can see both results on profil.php and the date from last result. I created a view vwresult that has these fields
id | ide | name | mark | date
---+-----+---------+------+-----------
1 | 1 | trickpd | 3 | 06.01.2018
1 | 2 | trickpd | 2 | 03.01.2018
5 | 3 | trickpd | 4 | 08.01.2018
5 | 4 | trickpd | 6 | 02.01.2018
That is my table with current result, insert new data in table will show more results in view table.
This is my code
$tst = mysqli_query($mysqli, "SELECT * FROM vwresult WHERE id=$ig AND name='trickpd' ORDER BY id, date desc");
$marks = [];
while($tstx = mysqli_fetch_assoc($tst)) {
$marks[] = $tstx['mark'];
}
After that I get stuck, and can't show the results.
The goal is:
to show mark 3 and 2 and date 06.01.2018 for id 1,
and when user opens details for id 5 to see results the will see 4, and 6 and also a 08.01.2018
Please help. Thank you all for your time.
Problem is with displaying the data.. I even create a two query one to show all the data and second with limit 1,1 but after that on script it's showing random data, not first and second result like I wont.. I'm trying to display last two results and the last date of inserting the data..

PHP MySql: Loop check row value if same as previous, add something at the last item of the group

Hello I need some help in grouping items. I have data like below.
id | area | cost
1 | a | 100
2 | b | 100
3 | a | 100
4 | c | 100
5 | c | 100
6 | a | 100
I want to achieve to display a table like below
id | area
1 | a
3 | a
6 | a
display total (sum of all area a)
2 | b
display total (sum of all area b)
4 | c
5 | c
display total (sum of all area c)
I can segregate all the rows order by area(asc) and arrange it by id(desc)
I am using the code below but doesnt do what I intended to do.
$itemdeleted = 1;
$query = $conn->prepare('
SELECT *
FROM projectscostbreakdown
WHERE projectscostbreakdown_projectid=:projectsid
&& projectscostbreakdown_deleted=:itemdeleted
GROUP
BY projectscostbreakdown_areaname ASC
, projectscostbreakdown_id DESC
');
$query->bindParam(':projectsid', $projectsid, PDO::PARAM_INT);
$query->bindParam(':itemdeleted', $itemdeleted, PDO::PARAM_INT);
$query->execute();
Then loop it
foreach ($query as $row) {
display id - area - cost
if (currentareavalue != previousareavalue)
display sum of all the previous costs with the same areaname
}
My problem is i want to display the total cost of every area at the end of the last entry of an area.
I am new to php and please bear with me.

php output from the database to html table

I have table entries in my database with structure:
id | card | event | time | day | hm
> id - is unique ID of each entry.
> card - is number.
> event - is number (0, 1, 2, or 3)
> time - is mysql_timestamp
> day - is day of month when entry was added (date("j", time())
> hm - some other info...
I want to display all entries for one month in html table.
Now I'm using this simple query:
$sql = "SELECT event, time, day, hm FROM `entries`
WHERE card=$card_t
AND YEAR(time)=$year
AND MONTH(time)=$month
AND event IN (0,1,3)
ORDER BY `time` ASC;";
Conditions of output:
table must have minimum one row for a day (31 rows for January).
if there is no entries for day(1-31) row must be:
if there is only two entries for day row must be:
<tr>
<td>$day_number</td>
<td>$time_of_first_event</td>
<td>$first_event</td>
<td>$time_of_last_event</td>
<td>$last_event</td>
</tr>
if there is more than two entries a day two must be (I will hide second one with jquery later):
<tr>
<td>$day_number</td>
<td>$time_of_first_event</td>
<td>$first_event</td>
<td>$time_of_last_event</td>
<td>$last_event</td>
</tr>
<tr>
<table>
<tr>
<td>$time</td>
<td>$event</td>
</tr>
</table>
</tr>
So it looks like:
| 1 | no entry |
| 2 | no entry |
| 3 | no entry |
| 4 | time_first | event_fisrt | time_last |event_last |
| time2 | event 2 |
| time3 | event 3 |
| 5 | no entry |
...
But all i got now is output of 31 row and if one day have more than it duplicates this day row and displays all rows for this day:
| 1 | no entry |
| 2 | no entry |
| 3 | no entry |
| 4 | time1 event 1 |
| 4 | time2 event 2 |
| 4 | time3 event 3 |
| 5 | no entry |
...
Please help me guys and sorry for mistakes, english is not my native lang.
Use GROUP_CONCAT in sql and explode foreach loop
$sql =
"SELECT
GROUP_CONCAT(event SEPARATOR ","), GROUP_CONCAT(time SEPARATOR ","),
day , GROUP_CONCAT(hm SEPARATOR ",") FROM `entries`
WHERE
card=$card_t
AND YEAR(time)=$year
AND MONTH(time)=$month
AND event IN (0,1,3)
GROUP BY
day
ORDER BY
`time` ASC;";
In foreach,
foreach ($entries as $entry) {
if ($entry['event'] == "") {
echo '<tr>';
echo '<td>'.$no++.'</td>';
echo '<td>No events</td>';
...................
echo </tr>';
continue;
}
$events = explode("," , $entry['event']);
if (count($events) > 0) {
// Have multiple row here
foreach($events as $event) {
........................
}
} else {
echo '<tr>';
echo '<td>'.$no++.'</td>';
echo '<td>'.$entry['event'].'</td>';
...................
echo </tr>';
}
}
You want to group the output, if I understand you correctly. And the criterion for building the groups is the date. One way would be to define a variable before your loop, in which you store the date of the last processed entry. And before you output the entry, you check whether the entry's date is the same as in this variable...then you are still within a group and should output it differently.
Might be a little difficult to achieve this in your case because of your very special output format. It might be easier to first loop over the query result and store the entries in a multidimensional array where the date is the key of the first level and in the next level you store all the entries related to this date. So you get:
array (
'xxxx-xx-xx' => array(entry1, entry2, entry3),
'yyyy-yy-yy' => array(entry1),
...
)
Then you can do another loop over this array and use if (count($array[$currentKey]) == 1) to check whether there is only a single event for this date or more.

counting multiple values in a row, going trugh columns twice in a row

I have a table that look like this:
Name | date1 | date2 | date3 | etc..
per1 | status1 | | status2 | etc
per4 | status2 | status3 | | etc
The number of the dates columns is not fixed. Their values can either be a status or they can be empty.
I want to access the data of the dates columns for each row separately and process the data.
The output I want to achieve:
Name | field1 | status1 | status2 | etc..
per1 | value | #ofstat1 | #ofstat2 | etc
So for I got, accessing the table at the beginning of the question:
$confirmed ="Confirmed";
$accepted ="Accepted";
while ($row = mysql_fetch_array($result)) {
$confirmed_cnt =0;
$accepted_cnt =0;
foreach ($row as $value) {
if (strcmp($value, $confirmed)) $confirmed_cnt++;
else if (strcmp($value, $accepted)) $accepted_cnt++;
}
print("<tr>");
print("<td>$row["Name"]</td>"); // name
print("<td>$confirmed</td>"); // confirmed
print("<td>$accepted</td>"); // accepted
print("</tr>");
}
As far as I know this should work, but for some reason it goes trough each column 2 times in a row.
Try mysql_fetch_assoc() or mysql_fetch_row() instead.
mysql_fetch_array() returns every column two times: as [1] and as ['fieldName']
Also, you have another error, replace your following line:
print("<td>$row["Name"]</td>"); // name
for this one:
print("<td>$row['Name']</td>"); // name

Categories