PHP membaca baris berdasarkan bulan
Seperti inilah tampilan tabel saya (ini hanya sebuah contoh, tabel saya berisi sejumlah besar baris):
ID | date | transfer | prov |
--------------------------------------------------------------
1 | 2020-08-21 14:13:14 | 2020-08-31 | 100 |
2 | 2020-08-21 14:13:14 | 2020-08-31 | 200 |
3 | 2020-08-21 14:13:11 | 2020-07-29 | 100 |
4 | 2020-08-20 13:05:59 | 2020-08-29 | 50 |
Ini kode saya:
<table>
<thead>
<tr>
<th>Januar</th>
<th>Februar</th>
<th>Mars</th>
<th>April</th>
<th>Mai</th>
<th>Juni</th>
<th>Juli</th>
<th>August</th>
<th>September</th>
<th>Oktober</th>
<th>November</th>
<th>Desember</th>
</tr>
<?php
$res = $link -> query("SELECT SUM(prov) as sum
FROM sales
WHERE YEAR(transfer) = YEAR(CURRENT_DATE())
GROUP BY MONTH(transfer)
ORDER BY MONTH(transfer)");
echo '<tr>';
while( $row = $res->fetch_assoc() ) {
echo "<td>$row[sum]</td>";
}
echo '</tr>';
?>
</thead>
</table>
Jadi ini pada dasarnya harus mengembalikan 250 untuk bulan Agustus, 100 untuk Juli dan 0 untuk bulan-bulan lainnya. Tapi saat menggunakan ini, hanya sel Januar dan Februar yang menampilkan nilainya, dan sel lainnya tidak ada. Apa yang saya lakukan salah?
Seperti inilah tampilannya saat live: https://ibb.co/8bd6JWP (12750 memiliki tanggal transfer di Agustus, bukan Januari, jadi semua sel harus memiliki nilai 0, tetapi Agustus harus 12750)
Jawaban
Anda tidak memeriksa nilai yang dikembalikan. Anda perlu selectbulan selain nilai agregat. Anda kemudian dapat memeriksa apakah bulan Anda di adalah bulan Anda memiliki nilai. Saya akan memilih semua nilai Anda terlebih dahulu, meletakkannya dalam sebuah array, kemudian mengulanginya selama berbulan-bulan dan memeriksa array tersebut untuk melihat apakah itu memiliki nilai.
Ide kasar:
$monthdata = array(7 => 10, 8 => 22 ); for($x =1; $x <= date('n'); $x++){
echo date('F', strtotime('2020-' . $x . '-01')) . PHP_EOL; if(!empty($monthdata[$x])) { echo $monthdata[$x];
} else {
echo 0;
}
echo PHP_EOL;
}
dan ubah kueri menjadi:
SELECT SUM(prov) as sum, MONTH(transfer) as month
agar bisa Anda gunakan $row['month']. Ini $monthdataharus dibangun sebagai:
$monthdata[$row['month']] = $row['sum'];
selama iterasi pemilihan.
Ingatlah bahwa SQL menangani kumpulan baris data. Data sampel dan kueri Anda menghasilkan sekumpulan dua baris data. Dan, kode php Anda membaca set itu dan menghasilkan <td>nnn</td>kolom tabel HTML untuk setiap baris di set Anda. Hanya ada dua. Karenanya hanya dua kolom di tabel HTML Anda. Itulah mengapa kode Anda tidak melakukan apa yang Anda inginkan. Biola db ini.https://www.db-fiddle.com/f/nfv5wDnBWWgP8dq8E26QtZ/0 mendemonstrasikan.
Pertanyaan yang lebih menarik: bagaimana Anda membuatnya bekerja? Ini sangat sulit sampai Anda terbiasa. Ada berbagai solusi. Favorit saya adalah menggunakan kueri yang menghasilkan kumpulan dua belas baris yang Anda inginkan dan kemudian KIRI BERGABUNG dengan data aktual Anda ke kumpulan itu.
MONTH(sometdate)menghasilkan bilangan bulat dalam kisaran [1-12]. Jadi jika Anda dapat menggunakan satu set dari dua belas bilangan bulat tersebut dalam kueri Anda, Anda akan mendapatkan apa yang Anda inginkan.
Coba ini.
SELECT SUM(prov) as sum
FROM seq_1_to_12
LEFT JOIN sales ON seq_1_to_12.seq = MONTH(transfer)
AND YEAR(transfer) = YEAR(CURRENT_DATE())
GROUP BY seq_1_to_12.seq
ORDER BY seq_1_to_12.seq
Jika Anda menggunakan varian MariaDB dari MySQL, tabel misterius seq_1_to_12 itu sudah ditentukan untuk Anda. Hore. Jika tidak, Anda perlu menentukannya sendiri dalam kueri Anda. Cara yang bagus adalah ini.https://www.db-fiddle.com/f/nfv5wDnBWWgP8dq8E26QtZ/1
SELECT seq_1_to_12.seq, IFNULL(SUM(prov),0) as sum
FROM (
SELECT 1 AS seq UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL
SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL
SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9 UNION ALL
SELECT 10 UNION ALL SELECT 11 UNION ALL SELECT 12
) seq_1_to_12
LEFT JOIN sales ON seq_1_to_12.seq = MONTH(transfer)
AND YEAR(transfer) = YEAR(CURRENT_DATE())
GROUP BY seq_1_to_12.seq
ORDER BY seq_1_to_12.seq
Perhatikan beberapa hal tentang ini.
IFNULL(SUM(prov,0))membuat kumpulan hasil menampilkan nol untuk data bulan Anda yang hilang, bukan nol. Itu membuat laporan Anda sedikit lebih bersih.- DIPERLUAS Anda harus menempatkan
YEAR(transfer) = YEAR(CURRENT_DATE())dalamONklausul AndaLEFT JOINdaripada di sebuahWHEREklausa. Mengapa? Ketika klausa WHERE (atau ORDER BY atau klausa GROUP BY) menyebutkan kolom dalam tabel LEFT JOINed, ini mengubah LEFT JOIN menjadi inner JOIN biasa. Operasi Inner JOIN menekan baris dari sisi kanan JOIN; LEFT JOIN melestarikan mereka. - Anda harus
GROUP BYdanORDER BYnilai urutan Anda.
Saya menulis artikel tentang ini beberapa waktu lalu.
Cobalah sesuatu seperti ini (solusi yang sedikit lebih bersih dan lebih mudah dipahami):
<?php
$months = array( 1 => 'Januar', 2 => 'Februar', 3 => 'Mars', 4 => 'April', 5 => 'Mai', 6 => 'Juni', 7 => 'Juli', 8 => 'August', 9 => 'September', 10 => 'Oktober', 11 => 'November', 12 => 'Desember'); ?> <table> <thead> <tr> <?php foreach($months as $month) echo "<th>$month</th>";
?>
</tr>
<?php
$res = $link -> query("SELECT MONTH(transfer) as month, SUM(prov) as sum
FROM sales
WHERE YEAR(transfer) = YEAR(CURRENT_DATE())
GROUP BY MONTH(transfer)
ORDER BY MONTH(transfer)"); // you don't need to order the results anymore
$results = array(); while($row = $res->fetch_assoc()){ $results[$row['month']] = $row['sum'];
}
echo '<tr>';
foreach($months as $m_id => $month){ if(isset($results[$m_id])) echo "<td>".$results[$m_id]."</td>";
else
echo "<td>0</td>";
}
echo '</tr>';
?>
</thead>
</table>