PHP Array Merge Issue - php

I have a table of races that have the race name, race id, and race date.
I am trying to build a single array (it has to be a single array returned via a function call) which would contain a list of the races in the following format:
,,---2017---
The Resolution AR, 58, 1.14.2017
Heartbreaker AR, 59, 2.11.2017
,,---2016---
The Blue Ridge AR, 38, 5.21.2016
The Fathers Day AR, 43, 6.18.2016
Adventure Bike (Santos), 54, 7.30.2016
,,---2015---
Gemini Springs AR, 4, 12.14.2015
I am almost there! But I am having one issue.
This is the current code I have:
function get_races() {
// get all the years that have races
$years = $wpdb->get_results("
select DATE_FORMAT(r.race_date,'%Y') year
from race_calendar r
group by DATE_FORMAT(r.race_date,'%Y')
order by DATE_FORMAT(r.race_date,'%Y') desc;
");
// loop through all years that have races
foreach ( $years as $year ) {
// add year header to array
$year_header = array(array ('','','---'.$year->year.'---'));
// get races for this particular year
$races = $wpdb->get_results("
select r.race_name
,r.race_id
,date_format(r.race_date,'%c.%d.%Y') race_date
from race_calendar r
where DATE_FORMAT(r.race_date,'%Y') = ".$year->year."
order by r.race_date;
", ARRAY_N);
// merge the year header and the races into an array
$merged_arr = array_merge($year_header, $races);
}
return $merged_arr;
}
// call function to get list of races
$races = get_races();
// display the list of races (with the year separator)
foreach ( $races as $race )
{
echo $race['0'] . ',' . $race['1'] . ',' . $race['2'] . '<br />';
}
It works. But problem is, that code above only displays the last iteration of the years loop, in this case, 2015:
,,---2015---
Gemini Springs AR, 4, 12.14.2015
Obviously $merged_arr is begin reset with each iteration of the years loop
How can I update it so that the resulting array in the function contains the data for all the iterations of the years loop?

You can do this all with a single query. Just select all the rows, then loop over the results and detect when the year changes from the previous iteration to know when to output your separator row.
$last = null;
$query = <select * from race_calendar order by race_date>
foreach ($query as $row) {
$year = // year of $row['race_date']
if ($year != $last) {
// new year, output separator line
$last = $year;
}
// output data line
}

Related

How to count sum of values from json objects in certain subdirectories seperately

I have 3 directories named september, october and november in the maindirectory 2021.
In all these 3 directories are json files which look like this:
{
"id": "id_2021-09-05_2200",
"date": "2021-09-05",
"guests": 32 // total guests for that day
}
For every month, i need the sum of all guests for that month. ( count all guests from all the json files in that month together).
I have this code so far but i get stuck in counting for each month:
$monthdirs = array_filter(glob('data/2021/*'), 'is_dir'); // read all month-dirs in year 2021
foreach($monthdirs as $monthdir) {
$monthfiles = glob($monthdir.'/*.json'); // all json files in a specific month
}
foreach($monthfiles as $monthfile) {
$arr[] = json_decode(file_get_contents($monthfile),true); // php assoc array
foreach($arr as $key => $val) {
$tot_guests_monthes[] += $val['guests']; // new array from each month with the sum of guests from all the json files in that month
}
}
foreach($tot_guests_monthes as $tot_guests_month) {
echo $tot_guests_month.'<br />';
}
I think in the 2nd foreach loop i am doing something wrong. My final output should be 3 values, something like:
200 // all guests september
300 // all guests october
400 // all guests november
$...[] = is basically a array_push, which means that $tot_guests_monthes[] += $val['guests']; will create a new element for each element of $arr of each $monthfile instead of summing.
Summing all values in a month and then adding them to $tot_guests_monthes should work:
$tot_guests_monthes = [];
$monthdirs = array_filter(glob('data/2021/*'), 'is_dir'); // read all month-dirs in year 2021
foreach($monthdirs as $monthdir) {
$monthfiles = glob($monthdir.'/*.json'); // all json files in a specific month
$sum = 0;
foreach($monthfiles as $monthfile) {
$arr = json_decode(file_get_contents($monthfile), true);
$sum += $arr['guests'];
}
$tot_guests_monthes[] = $sum;
}
foreach($tot_guests_monthes as $tot_guests_month) {
echo $tot_guests_month.'<br />';
}

Combining while in foreach in PHP

I have been working for a while to combine a "foreach loop" and a "while loop". I would like my foreach to run 30 times. This is indicated by $counter. Now the problem is that my "while" again starts the "foreach" every time. But it hears 30 times turning the "while" each time again.
If I get the while part away and use static code, it will work completely. But I need to link my DB for the information. Perhaps an option is to make a "foreach" a "for" or a whole different option. But I have no idea how to set him up.
$counter = days in a month
$index = foreach time for running. Max $counter
$NUM = unique number of 1 people
The $ index together with $ cut_startday together indicate when a box is to be red or green.
Here's the code for the none working foreach:
foreach(range(1,$counter) as $index) {/*open foreach*/
$get_data = "
SELECT *
FROM core";
$result1 = $conn->query($get_data) or die($conn ->error);
//Start query 1
if($result1) {
while($row = $result1->fetch_assoc()) {
// Get NUM, START DATE and END DATE
$NUM = ($row['c_m_num']);
$startdate = ($row['e_date_s']);
$enddate = ($row['e_date_e']);
// Cut strings for date
$sort_year = substr($startdate, 6, 4); // START YEAR -> 2017
$sort_month = substr($startdate, 0, 2); // START MONTH -> 09
$cut_startday = substr($startdate, 3, 2); // START DAY -> 17
$cut_endday = substr($enddate, 3, 2); // END DAY -> 19
if($load_m_NUM == "$NUM" and $index >= $cut_startday && $index <= $cut_endday ){
echo"<td style='background-color:red;'>x</td>";
}
else{
echo"<td style='background-color:green;'></td>";
}
}
}
/*end foreach*/ }
What the idea is of the code. I want a calendar with a top row de days of a month and on the left side al the people. If the core find a match between days and 1 men, color the td red if not color green.
Any help greatly appreciated!
You could change the foreach statement to for ($index = 0; $index < 30; $index++). To improve your code I suggest putting the for loop inside the while loop instead. That way you only query the database once instead of 30 times.

sum of 2D array in php

I have a situation where I need to generate total sales of each month.
I can show total sales of 12 month in a certain area but I need to show total sales of any month of a certain area. i.e: total sales of June at Head Office area.
my sample code is as follows:
while($area = mysql_fetch_array($exe_area))
{
for ($m=1; $m<=12; $m++) {
.........
echo $total_sold;
$sales_of_year+= $total_sold;
} // end of month listing....
echo $sales_of_year;
} // end of area listing...
U may try this !!!
$tmp = explode( '|', $str );
$data = array();
foreach ( $tmp as $k => $v )
{
$data[] = explode( ',', $v );
}
It looks like your data is being retrieved from the database, in which case you can extract the total sum with your query:
SELECT SUM(column_name) FROM table_name;
Or, to analyse a particular month, depending on your database schema, you can do:
SELECT SUM(column_name) FROM table_name WHERE month = 'June';

Adding rows to an array in PHP

I have loaded an associative array of records from a MySQL database table.
The array consists of 1 to 7 rows representing one week of entries,
which might not have been entered for each day.
How can I insert blank rows into the array for the missing days
so that I can easily display the data in a table?
I don't need to update the database with the blanks.
Example:
Field1 Field2 Field3 Field4 .... Field#
Record[0]
Record[1]
Record[2]
Record[3]
Record[4]
Record[5]
Record[6]
Field4 is the date as yyyy-mm-dd
I load the array automatically using a start date and end date
Some weeks there will be a Sun, Tue, and Fri or Mon, Tue, Wed, Fri & Sat.
this is simple:
Do you know how many "Fields" you have for each day? let's say it's "num of fields"
$records = array_fill(0, 7, array_fill(0, <num of fields>, ''));
what this does is it creates a blank array from [0] to [6] and for each array element it inserts another array of "Fields", with "num of fields", each of which is set to an empty string ''.
Now that you have this, you read your data from the mysql table and if you selectively assign $records by index (i'm assuming), the rest of them will stay blank.
Keep in mind that you can reassign an element of $records array by using something like
$records[5] = array('New value', 'Field2 value');
which is what you do when you read data from mysql table.
Do you use some kind of index in your mysql table to correspond to the numbered day in a week?
comment here if you get stuck with mysql part.
If your array is associative, then when constructing the table why not just check for and skip the empty rows? As an example:
Example 1:
if ($row['Monday'] == '')
{
// draw blank template
}
else
{
// draw using live data
}
Based on added example (untested; for php 5.1 and above):
Example 2:
for($i = 0; $i < count($Record); $i++)
{
$recordDate = strtotime($Record[$i][field4]);
$dayOfWeek = $date('N', $recordDate);
switch ($dayOfWeek)
{
case '1':
// Monday
break;
case '2':
// Tuesday
break;
// and so on...
}
}
Edit
The above code assumed that your rows are in weekday order, with possible omissions. The problem with the first example, is that the array is not associative quite like the example. The problem with the second example, is that a missing weekday row results in a completely skipped output, which could provide a table like MTWFS (skipped Thursday).
So, you need to build a loop that draws each day of the week, and checks all of the rows for the appropriate day to draw. If the day is not found, an empty day is drawn:
Example 3:
$dayNames = {'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'};
// Loop that walks the days of the week:
for($d = 1; $d < 7; $d++)
{
// Loop that checks each record for the matching day of week:
$dayFound = false;
for($i = 0; $i < count($Record); $i++)
{
$recordDate = strtotime($Record[$i][field4]);
$dayOfWeek = $date('N', $recordDate);
// output this day name in your own formatting, table, etc.
echo $dayNames[$i];
if ($dayOfWeek == $d)
{
// output this day's data
$dayFound = true;
break;
}
if (!$dayFound)
{
// output a blank template
}
}
}
Edit 2
Ok it seems you are more interested in having a fully populated array of weekdays than an output routine (I was assuming you would just want to draw the tables in php or something). So this is my example of how to arrive at a 7-day array with no gaps:
Example 4:
$weekData = array(); // create a new array to hold the final result
// Loop that walks the days of the week, note 0-based index
for($d = 0; $d < 6; $d++)
{
// Loop that checks each record for the matching day of week:
$dayFound = false;
for($i = 0; $i < count($Record); $i++)
{
$recordDate = strtotime($Record[$i][field4]);
$dayOfWeek = $date('N', $recordDate);
// Add one to $d because $date('N',...) is a 1-based index, Mon - Sun
if ($dayOfWeek == $d + 1)
{
// Assign whatever fields you need to the new array at this index
$weekData[$d][field1] = $Record[$i][field1];
$weekData[$d][field2] = $Record[$i][field2];
$weekData[$d][field3] = $Record[$i][field3];
$weekData[$d][field4] = $Record[$i][field4];
// ...
break;
}
if (!$dayFound)
{
// Assign whatever default values you need to the new array at this index
$weekData[$d][field1] = "Field 1 Default";
// ...
}
}
}
Without having seen your current code (as requested in the comments by Felix Kling), my guess is that you will need to loop through your array, passing it to a function (or passing the array to the function) which checks Field4 and keeps track of which days of that week have data and fills in those missing days. This would be easier if the array was in order to start with (as you would only need to track the previous 'entry' rather than the entire week).
I'm a bit busy currently, here's some pseduo-code that will need to be expanded etc.
$formattedWeek = getFormattedWeek($inputArray);
function getFormattedWeek($input) {
$nextDay = 'Sunday';
foreach ($input as $entry) {
if (date-call-that-returns-day-of-the-week !== $nextDay) {
$output[] = 'add whatever you need to your array';
} else {
$output[] = $entry;
}
$nextDay = call-to-increase-the-day-or-loop-back-to-Sunday();
}
return $output;
}
You should get the picture.

How to break up reports by month with php and mysql?

I'm trying to do something relatively simple here. Basically I have a table with a bunch of rows in it marked with a timestamp (format: 2009-05-30 00:14:57).
What I'm wanting to is do is a query which pulls out all of the rows, and splits them by the month so I'm left with a final result like:
February
rowID name order date
rowID name order date
rowID name order date
January
rowID name order date
rowID name order date
rowID name order date
etc.
I have a few vague ideas how to do this - they just seem long winded.
One of the ways would be to do a query for each month. I'd derive what the current month is in PHP then construct a for() which goes back a certain number of months.
like:
$currentmonth = 8;
$last6months = $currentmonth - 6;
for($i = $currentmonth; $i == $last6months; $i--) {
$sql = 'SELECT * FROM reports WHERE MONTH(reports.when) = $currentmonth ';
$res = mysql_query($sql);
// something would go here to convert the month numeral into a month name $currentmonthname
echo $currentmonthname;
while($row = mysql_fetch_array($res)) {
// print out the rows for this month here
}
}
Is there a better way to do this?
It's better to fetch all data once,ordered by month..
Then while fetching with php you can store your current month in a variable (for example $curMonth) and if there is a change in the month, you echo "New Month"...
Executing a query is slow, it's better to minimize your "conversations" with the db..
Don't forget that you have to deal with years aswell. If you have two records, one for January '09 and one for January '08, your results may be skewed.
Best to follow Svetlozar's advice and fetch all data at once. Once you have it in memory, use PHP to segment it into something usefull:
$monthData = array();
$queryResult = mysql_query("
SELECT
*,
DATE_FORMAT('%m-%Y', when) AS monthID
FROM
reports
WHERE
YEAR(when) = 2009 AND
MONTH(when) BETWEEN 5 and 11
");
while ($row = mysql_fetch_assoc($queryResult))
{
if (!isset($monthData[$row['monthID']]))
$monthData[$row['monthID']] = array();
$monthData[$row['monthID']][] = $row;
}
mysql_free_result($queryResult);
foreach($monthData as $monthID => $rows)
{
echo '<h2>Data for ', $monthID, '</h2>';
echo '<ul>';
foreach($rows as $row)
{
echo '<li>', $row['someColumn'], '</li>';
}
echo '</ul>';
}
You could change your SQL query to get your entire report. This is much more efficient than querying the database in a loop.
select
monthname(reports.when) as currentmonth,
other,
fields,
go,
here
from reports
order by
reports.when asc
You could then use this loop to created a nested report:
var $currentMonth = '';
while($row = mysql_fetch_array($res)) {
if($currentMonth !== $row['currentMonth']) {
$currentMonth = $row['currentMonth']);
echo('Month: ' . $currentMonth);
}
//Display report detail for month here
}
*Note: Untested, but you get the general gist of it I'm sure.
This is the SQL script:
SELECT*, DATE_FORMAT(fieldname,'%Y-%m') AS report FROM bukukecil_soval WHERE MONTH(fieldname) = 11 AND YEAR(fieldname)=2011
I hope you know where you should put this code :D

Categories