问题
I've created an auto-populating array in a counted loop for each month using timestamps, e.g 2016-06-11 00:00:00 - the database layout that the loop is fetching from is:
TimeRecord | Views
2016-06-11 00:00:00 | 22
2016-08-11 00:00:00 | 44
Now, the above example skips the 07 (July) month, there is NO DATA for this month, and so when the loop goes through this month, it should return either null or 0, but it returns the previously known number (which is 22 in this case).
For 2016-09, there is no specified data, so the array will give "44".
The code for the loop and fetching from the database to generate the array is like so:
$startMonth = date("y-m-d");
$endMonth = date("y-m-d");
while ($Month <= 12){
$ViewsThisMonth = mysqli_fetch_object(mysqli_query($db, "SELECT SUM(Views) AS NumberFinalViews, EXTRACT(YEAR_MONTH FROM TimeRecord) AS YearMonth FROM BlogViews WHERE TimeRecord > '$startMonth' AND TimeRecord < '$endMonth' GROUP BY YearMonth"));
if (is_null($ViewsThisMonth->NumberFinalViews)){
$ViewsThisMonth->NumberFinalViews = 0;
}
$ArrayTimeStamp[] = $ViewsThisMonth->NumberFinalViews;
$Month = $Month + 1;
$startMonth = date("y-m-d",strtotime("-$Month month"));
}
An example returned JSON Encoded Array is:
[0,"29392","333","4000","4000","99","99","99","99","99","99","99"]
A screenshot of the database values that caused the above array can be found here. As you can see, 4000 repeats itself twice as there is no record for the 5th month, causing it to use the 4th month's data. 99 is also repeated, as there are no values for the 6th-12th month, therefore it uses the 6th month's value instead of returning a 0.
If there is no TimeRecord for that month when the loop goes through, I want it to return 0, not assume that the view number is the same as the previous month.
回答1:
The problem is that you perform the same query multiple times, albeit with a changing date. The query is designed to give a result for several months, yet you only use one of the result rows. As there is no order by
clause, it could be that you get the rows in an unexpected order. Also the way you change the start date in the loop is strange: it moves backwards in time.
It would be better to execute the query only once, and then store the results into a prepared array that is keyed by month-year.
Note that you can perform the null check in the SQL query itself with COALESCE
.
The code becomes something like this:
$startYearMonth = date('Ym', strtotime("2015-01-01")); // set this date as you wish
$endYearMonth = date('Ym', strtotime("now"));
// Prepare result array: one entry per month, with all values set to 0
for ($yearMonth = $startYearMonth; $yearMonth <= $endYearMonth;
$yearMonth += ($yearMonth % 100 == 12 ? 89 : 1)) {
$months[$yearMonth] = 0;
}
// improved query
$result = mysqli_query($db, "
SELECT COALESCE(SUM(Views), 0) AS NumberFinalViews,
EXTRACT(YEAR_MONTH FROM TimeRecord) AS YearMonth
FROM BlogViews
WHERE EXTRACT(YEAR_MONTH FROM TimeRecord)
BETWEEN '$startYearMonth' AND '$endYearMonth'
GROUP BY YearMonth");
// Featch and store each result in their proper year-month slot
while ($ViewsThisMonth = mysqli_fetch_object($result)) {
$months[$ViewsThisMonth->YearMonth] = $ViewsThisMonth->NumberFinalViews;
}
// output the result
print_r($months);
来源:https://stackoverflow.com/questions/39348799/array-loop-assuming-nil-data