mysql-PHPは$intervalに基づいてX回ループしますが、残りの値を処理するにはどうすればよいですか?
[フォローアップの質問で更新されました。edit4を参照してください]
つまり、連続する日付のX個のスコア平均を返す関数があります。しかし、私は残りの値を処理するのが好きです。
たとえば、次の行が見つかった場合(ランダムデータとハードコードされたpersonid = 133に基づく)
PHP関数getConsecutiveInterval(4);を呼び出したときに得られる平均出力。
Total Found: 10
Num Of Loops: 2.5
2.75
3.5
そして平均は
になると思います 2.75, 3.5 and 3.5(based on the rest 2 dates not 4)
そしてgetConsecutiveInterval(3);を使用する場合平均値は
になると思います 3.33, 3.33, 2.66 and 4 (based on 1 date)
そして私は
Total Found: 10
Num Of Loops: 3.3333333333333
3.3333333333333
3.3333333333333
2.6666666666667
では、残りの行を平均として返す/処理するにはどうすればよいですか?
これはphp関数です:
function getConsecutiveInterval($interval) {
//$interval Num Of Consecutive Days
global $conn;
$offset = '';
// Query is the same and at the end of it you include LIMIT to be controlled by the loop.
$q = "SELECT a.purdate, b.score, a.status FROM records a INNER JOIN scores2 b ON a.purdate = b.date AND a.personid = b.personid WHERE a.personid = 133 AND a.status IN('P','T') ORDER BY purdate ASC, score DESC ";
//Total Found Use To Divide by
$result = mysqli_query($conn, $q);
$num_rows = mysqli_num_rows($result);
echo 'Total Found: '.$num_rows.'<br/>';
$numOfLoops = $num_rows/$interval;
echo 'Num Of Loops: '. round($numOfLoops).'<br/>';
// For loop will control the results sets divided by 4
for ($i = 1; $i <= $numOfLoops; $i++) {
// To add the offset after the first set
if ($offset > 0) {
$limitValues = $offset. ", " . $interval . " ";
} else {
$limitValues = $interval;
}
$sqlquery = $q . " LIMIT " . $limitValues;
$avg = 0;
$total = 0;
//Total Found Use To Divide by
$result = mysqli_query($conn, $q);
$num_rows = mysqli_num_rows($result);
//echo 'Total Found: '.$num_rows;
foreach (mysqli_query($conn, $sqlquery) as $results) {
// Do Something
$total += $results['score'];
$avg = $total / $interval;
print_r($results['purdate'].' <-> ');
//see [edit2] need only the first date in assoc array?? $results['purdate'][0] doesn't work
}
echo $avg . '<br/>';
$offset += $interval;
}
}
[edit1] 各間隔のstartDateを取得するためのコードと、残りの値を処理するためのstartのコードを追加します
function getConsecutiveInterval($interval) {
//$interval Num Of Consecutive Days
global $conn;
$offset = '';
// Query is the same and at the end of it you include LIMIT to be controlled by the loop.
$q = "SELECT a.purdate, b.score, a.status FROM records a INNER JOIN scores2 b ON a.purdate = b.date AND a.personid = b.personid WHERE a.personid = 133 AND a.status IN('P','T') ORDER BY purdate ASC, score DESC ";
//Total Found Use To Divide by
$result = mysqli_query($conn, $q);
$num_rows = mysqli_num_rows($result);
echo 'Total Found: '.$num_rows.'<br/>';
$numOfLoops = floor($num_rows/$interval);
echo 'Num Of Loops: '. $numOfLoops.'<br/>';
$rest = $num_rows - ($interval*$numOfLoops);
echo 'Rest: '.$rest.'<br/>';
$arrFound = [];
// For loop will control the results sets divided by 4
for ($i = 1; $i <= $numOfLoops; $i++) {
// To add the offset after the first set
if ($offset > 0) {
$limitValues = $offset. ", " . $interval . " ";
} else {
$limitValues = $interval;
}
$sqlquery = $q . " LIMIT " . $limitValues;
$avg = 0;
$total = 0;
//Total Found Use To Divide by
$result = mysqli_query($conn, $q);
$num_rows = mysqli_num_rows($result);
//echo 'Total Found: '.$num_rows;
$j = 0;
foreach (mysqli_query($conn, $sqlquery) as $results) {
if ($j == 0) {
echo $results['purdate'];
$arrFound[$i]['date'] = $results['purdate'];
}
// Do Something
$total += $results['score'];
$avg = $total / $interval;
$j++;
}
$arrFound[$i]['avg'] = $avg;
echo $avg . '<br/>';
$offset += $interval;
}
print_r($arrFound);
}
[edit2] 最後に、各間隔の開始パーデートも配列に返される必要があります。
[edit3]
別のテーブルには似たようなものが必要ですが、コードごとに出力する必要があります。クエリは次のようになります:
$q = "SELECT date, code
FROM Records2
WHERE studentid = 131
AND date >= '2017-02-10' AND date <= '2017-06-13'
AND code IN ('P','T','L','U')
ORDER BY date ASC;";
そしてastrangeloopの助けを借りて、私はこれがコードごとに出力するのも好きです。これは、x軸が開始日で、y軸がP、T、L、またはUの数をプロットするチャートをプロットするためのものです(ほとんどの場合、PとT)
$intervals = array();
foreach (array_chunk($records, $interval_size) as
$interval_records) {
$first_record = reset($interval_records);
$interval = array(
'start' => $first_record['date'],
'codes' => array_column($interval_records, 'code'),
/*Is It Possible to Order and/or Calculate with the
code values? Like another array*/,
);
$intervals[] = $interval;
}
return $intervals;
現時点では、これが返されます:
[5] => Array
(
[start] => 2017-03-23
[codes] => Array
(
[0] => P
[1] => P
[2] => P
[3] => P
[4] => P
)
[count] => 5
)
そして私はこのように見えるjs出力が好きです:
['start', #num_of_codes_P, #num_of_codes_T, #num_of_codes_L, #num_of_codes_U,'count'],
['start', #num_of_codes_P, #num_of_codes_T, #num_of_codes_L, #num_of_codes_U,'count'],
将来の参考のために、実行可能な解決策を見つけたと思います(通知エラーのため、array_count_valuesを使用していません)。これがコードの取得方法です。
$records = getRecordsWithIntervals($records, 5);
foreach ($records as $record) {
echo count(array_keys($record['codes'], 'P')).', '.count(array_keys($record['codes'], 'U')).'<br/>';
}
[edit4]これは別の質問で質問する必要がありますが、interval_sizeを週次、月次、または四半期のカスタマイズに設定する機能を追加するにはどうすればよいですか(カスタムbeginDate-endDate =教育年を4つ以上に分割)< / p>
答え :
解決策:
データベースからすべてのスコアを一度に選択するクエリがすでにあるため、1つの可能なアプローチは、間隔ごとにデータベースを再度クエリするのではなく、phpでこれを行うことです。データベースからすべてを一度にフェッチしてから、phpの array_chunk()
関数を使用して、配列を目的の間隔にスライスし、そこから平均などを計算できます。
function getRecords()
{
global $conn;
$sql = "
SELECT a.purdate
, b.score
, a.status
FROM records a
JOIN scores2 b
ON a.purdate = b.date
AND a.personid = b.personid
WHERE a.personid = 133
AND a.status IN('P','T')
ORDER
BY purdate ASC
, score DESC
;
";
$result = mysqli_query($conn, $sql);
$records = mysqli_fetch_all($result, MYSQLI_ASSOC);
mysqli_free_result($result);
return $records;
}
function getIntervalsWithAverageScores(array $records, $interval_size)
{
$intervals = array();
foreach (array_chunk($records, $interval_size) as $interval_records) {
$first_record = reset($interval_records);
$interval = array(
'start' => $first_record['purdate'],
'scores' => array_column($interval_records, 'score'),
'count' => count($interval_records),
'average' => array_sum(array_column($interval_records, 'score')) / count($interval_records),
);
$intervals[] = $interval;
}
return $intervals;
}
これらの関数を次のように使用します:
$records = getRecords();
var_dump(getIntervalsWithAverageScores($records, 4));
var_dump(getIntervalsWithAverageScores($records, 3));
このような出力を提供します(php 5.6でテスト済み):
array(3) {
[0]=>
array(4) {
["start"]=>
string(10) "2015-06-11"
["scores"]=>
array(4) {
[0]=>
string(1) "5"
[1]=>
string(1) "2"
[2]=>
string(1) "3"
[3]=>
string(1) "1"
}
["count"]=>
int(4)
["average"]=>
float(2.75)
}
[1]=>
array(4) {
["start"]=>
string(10) "2016-01-02"
["scores"]=>
array(4) {
[0]=>
string(1) "5"
[1]=>
string(1) "4"
[2]=>
string(1) "4"
[3]=>
string(1) "1"
}
["count"]=>
int(4)
["average"]=>
float(3.5)
}
[2]=>
array(4) {
["start"]=>
string(10) "2016-10-13"
["scores"]=>
array(2) {
[0]=>
string(1) "3"
[1]=>
string(1) "4"
}
["count"]=>
int(2)
["average"]=>
float(3.5)
}
}
// second internal array omitted ...
配列の最後のエントリのカウントは2で、スコアは4ではなく2であることがわかります。
余談ですが、将来ハードコードされた値の代わりにユーザー入力を使用する場合は、SQLインジェクションから身を守るためにプリペアドステートメントの使用を検討してください。
同様の質問
私たちのウェブサイトで同様の質問で答えを見つけてください。