PHP đọc các hàng dựa trên tháng
Đây là cách bảng của tôi trông như thế nào (đây chỉ là một ví dụ, bảng của tôi chứa một lượng lớn các hàng):
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 |
Đây là mã của tôi:
<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>
Vì vậy, về cơ bản giá trị này sẽ trả về 250 cho tháng 8, 100 cho tháng 7 và 0 cho các tháng còn lại. Nhưng khi sử dụng điều này, chỉ ô Januar và Februar hiển thị giá trị, còn các ô khác không ở đó. Tôi đang làm gì sai?
Đây là cách nó trông giống như trực tiếp: https://ibb.co/8bd6JWP (12750 có ngày chuyển vào tháng 8, không phải tháng 1, vì vậy tất cả các ô phải có giá trị 0, nhưng tháng 8 phải có 12750)
Trả lời
Bạn không kiểm tra các giá trị trả về. Bạn cần đến selecttháng ngoài các giá trị tổng hợp. Sau đó, bạn có thể kiểm tra xem tháng của bạn có phải là tháng bạn có giá trị hay không. Trước tiên, tôi sẽ chọn tất cả các giá trị của bạn, đặt chúng vào một mảng, sau đó lặp lại qua các tháng và kiểm tra mảng để xem nó có giá trị hay không.
Ý tưởng sơ lược:
$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;
}
và thay đổi truy vấn thành:
SELECT SUM(prov) as sum, MONTH(transfer) as month
để bạn có thể sử dụng $row['month']. Các $monthdatanên được xây dựng như:
$monthdata[$row['month']] = $row['sum'];
trong quá trình lặp lại lựa chọn.
Hãy nhớ rằng SQL xử lý tập hợp các hàng dữ liệu. Dữ liệu mẫu và truy vấn của bạn tạo ra một tập hợp hai hàng dữ liệu. Và, mã php của bạn đọc tập hợp đó và tạo <td>nnn</td>cột bảng HTML cho mỗi hàng trong tập hợp của bạn. Chỉ có hai người trong số họ. Do đó chỉ có hai cột trong bảng HTML của bạn. Đó là lý do TẠI SAO mã của bạn không làm những gì bạn muốn. Db-fiddle này.https://www.db-fiddle.com/f/nfv5wDnBWWgP8dq8E26QtZ/0 biểu tình.
Câu hỏi thú vị hơn: làm thế nào để bạn làm cho nó hoạt động? Nó phức tạp một cách đáng ngạc nhiên cho đến khi bạn quen với nó. Có nhiều giải pháp khác nhau. Yêu thích của tôi là sử dụng một truy vấn tạo ra tập hợp mười hai hàng bạn muốn và sau đó LEFT THAM GIA dữ liệu thực tế của bạn vào tập hợp đó.
MONTH(sometdate)tạo ra các số nguyên trong phạm vi [1-12]. Vì vậy, nếu bạn có thể sử dụng tập hợp mười hai số nguyên đó trong truy vấn của mình, bạn sẽ có những gì bạn muốn.
Thử cái này.
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
Nếu bạn sử dụng biến thể MariaDB của MySQL, bảng bí ẩn đó seq_1_to_12đã được xác định cho bạn. Hoan hô. Nếu không, bạn cần tự xác định nó trong truy vấn của mình. Một cách tốt là đây.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
Lưu ý một số điều về điều này.
IFNULL(SUM(prov,0))làm cho tập kết quả hiển thị số không cho dữ liệu tháng bị thiếu của bạn thay vì giá trị rỗng. Nó làm cho báo cáo của bạn sạch sẽ hơn một chút.- MỞ RỘNG Bạn cần đặt
YEAR(transfer) = YEAR(CURRENT_DATE())trongONmệnh đề của bạnLEFT JOINchứ không phải trong mộtWHEREmệnh đề. Tại sao? Khi mệnh đề WHERE (hoặc mệnh đề ORDER BY hoặc GROUP BY) đề cập đến một cột trong bảng LEFT JOINed, nó sẽ chuyển LEFT JOIN thành một JOIN bên trong bình thường. Các hoạt động bên trong JOIN ngăn chặn các hàng từ phía bên phải của JOIN; LEFT JOIN sẽ bảo vệ chúng. - Bạn phải
GROUP BYvàORDER BYcác giá trị trình tự của bạn.
Tôi đã viết một bài báo về điều này một thời gian trước đây.
Hãy thử một cái gì đó như thế này (giải pháp dễ hiểu và dễ hiểu hơn một chút):
<?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>