基于公式计算结果的条件计数问题及数据库设计疑问
问题分析与解决方案
现有代码的核心问题
你的统计结果不符合预期(10条数据仅返回8条),主要源于两个关键问题:
- COUNT函数的特性限制:
count(ketebalan-(toleransi/10))会自动忽略计算结果为NULL的行。如果有2条数据的ketebalan或toleransi字段为NULL,计算后结果就是NULL,不会被计入统计。若要统计所有符合过滤条件的行(包括计算结果为NULL的),可以用COUNT(*);若要精准统计计算结果非NULL的行,可改用COUNT(IF(ketebalan-(toleransi/10) IS NOT NULL, 1, NULL))。 - 无关联的表连接导致笛卡尔积:SQL中直接拼接
tb_coring和tb_coredrill,未指定表间关联条件(比如tb_coring.关联字段 = tb_coredrill.关联字段),这会让两张表的符合条件数据做笛卡尔积相乘,统计出的数量完全失真,这才是更严重的问题。
另外,代码存在SQL注入风险,直接将$_GET参数拼入SQL语句,极易被攻击,必须改用MySQLi预处理语句。
是否需要新增数据库列存储计算结果?
分两种场景判断:
- 若该计算值频繁被查询/统计:推荐新增列,优先用MySQL的生成列(Generated Column),无需手动维护,数据库会自动根据公式计算并存储值。示例语句:
后续统计直接调用该列,既高效又避免重复计算。ALTER TABLE tb_coring ADD COLUMN mintebal DECIMAL(10,2) GENERATED ALWAYS AS (ketebalan-(toleransi/10)) STORED; - 若仅偶尔用到该计算值:无需新增列,修正现有SQL即可。示例修正后的代码(需根据实际表结构调整关联字段):
if (isset($_GET['tanggal'])) { $tgl=trim($_GET['tanggal']); $material=trim($_GET['material']); $proyek=trim($_GET['proyek']); // 用预处理语句避免SQL注入,同时修正表关联逻辑 $sql = "SELECT COUNT(CASE WHEN ketebalan-(toleransi/10) IS NOT NULL THEN 1 END) as mintebal FROM tb_coring JOIN tb_coredrill ON tb_coring.kode_coring = tb_coredrill.kode_coring WHERE tb_coring.kode_material=? AND tb_coring.kode_proyek=? AND tb_coredrill.kode_material=? AND tb_coredrill.kode_proyek=? AND tb_coring.tanggal_coring=?"; $stmt = mysqli_prepare($db, $sql); mysqli_stmt_bind_param($stmt, "sssss", $material, $proyek, $material, $proyek, $tgl); mysqli_stmt_execute($stmt); $hasil = mysqli_stmt_get_result($stmt); } $no=0; while ($data = mysqli_fetch_array($hasil)) { ?> <tr> <td>Jumlah Data : <?php echo $data['mintebal']; ?></td> </tr> <?php }
内容的提问来源于stack exchange,提问作者Fachri Saputra
相关产品推荐
相关产品推荐

