PHP membaca baris berdasarkan bulan

Aug 27 2020

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

1 user3783243 Aug 27 2020 at 12:04

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.

1 O.Jones Aug 27 2020 at 11:47

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())dalam ONklausul Anda LEFT JOINdaripada di sebuah WHEREklausa. 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 BYdan ORDER BYnilai urutan Anda.

Saya menulis artikel tentang ini beberapa waktu lalu.

1 FlashThunder Aug 27 2020 at 12:15

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>