You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决MySQL中‘Subquery returns more than 1 row’错误(CodeIgniter场景)

问题原因分析

这个错误很常见,咱们先拆解下问题:你写的每个子查询里都加了GROUP BY tanggal,这会让子查询返回所有日期的统计结果(多行数据),但外层查询期望每个主查询行(对应单个日期)只能拿到子查询的一个单一值,数据库自然就报错了。

举个直观的例子:子查询SELECT COUNT(*) from absensi_siswa where kehadiran="alfa" GROUP BY tanggal会返回每个日期的alfa人数,是一个多行结果集,但外层查询需要的是当前行日期对应的alfa人数,所以子查询必须返回单个值才行。


解决方案1:修正子查询,添加关联条件

给每个子查询加上WHERE条件关联外层的日期,同时去掉子查询里的GROUP BY(因为已经过滤到单个日期了):

$query = $this->db->query('
    SELECT 
        tanggal,
        (SELECT COUNT(*) FROM absensi_siswa AS sub WHERE sub.kehadiran="alfa" AND sub.tanggal = main.tanggal) AS alfa,
        (SELECT COUNT(*) FROM absensi_siswa AS sub WHERE sub.kehadiran="izin" AND sub.tanggal = main.tanggal) AS izin,
        (SELECT COUNT(*) FROM absensi_siswa AS sub WHERE sub.kehadiran="hadir" AND sub.tanggal = main.tanggal) AS hadir,
        (SELECT COUNT(*) FROM absensi_siswa AS sub WHERE sub.kehadiran="sakit" AND sub.tanggal = main.tanggal) AS sakit
    FROM absensi_siswa AS main
    GROUP BY tanggal
');
return $query->result();

这里给主表起了别名main,子表起了别名sub,通过sub.tanggal = main.tanggal让子查询只统计当前主行日期的对应状态人数,每个子查询都会返回单个值,就不会触发报错了。


解决方案2:使用条件聚合(更高效,推荐)

上面的方法需要多次扫描表(每个子查询扫一次),数据量大的时候性能会打折扣。更优的方式是用条件聚合,只扫描一次表就能完成所有统计:

$query = $this->db->query('
    SELECT 
        tanggal,
        SUM(CASE WHEN kehadiran = "alfa" THEN 1 ELSE 0 END) AS alfa,
        SUM(CASE WHEN kehadiran = "izin" THEN 1 ELSE 0 END) AS izin,
        SUM(CASE WHEN kehadiran = "hadir" THEN 1 ELSE 0 END) AS hadir,
        SUM(CASE WHEN kehadiran = "sakit" THEN 1 ELSE 0 END) AS sakit
    FROM absensi_siswa
    GROUP BY tanggal
');
return $query->result();

原理很简单:CASE WHEN会逐行判断当前记录的状态,符合就返回1,否则返回0,再用SUM把同一日期的数值累加,就是该状态的总人数。这种方法只需要遍历一次表,性能比子查询好很多。


内容的提问来源于stack exchange,提问作者Cinta Dewi Amelia

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:05:52