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

PHP/MySQL中INSERT INTO报错:子查询返回多行(无显式子查询)

问题:INSERT语句无子查询却返回“Subquery returns more than 1 row”错误

我正在用PHP和MySQL开发网站,执行这段PHP代码时遇到了奇怪的错误:

$sql = sprintf("INSERT INTO request_boms SET request_list_id = %d, project_version_id = %d, amount = %d, user = '%s', timestamp = %d", $requestNo, $bomID, $amount, $_SESSION["admin_user_name"], time());
$this->db_inventory->Execute($sql);

已经确认$this->db_inventory的数据库连接是正常的,但执行后返回错误:Subquery returns more than 1 row,对应的SQL语句是:

INSERT INTO request_boms SET request_list_id = 14, project_version_id = 429, amount = 1, user = 'admin', timestamp = 1607510083

我查了相关案例,发现所有案例的查询里都包含SELECT子查询,但我的INSERT语句根本没用到SELECT,这到底是怎么回事?

补充一下我的Execute()方法和RecordSet类代码:

public function Execute($sql) {
    $rs = new RecordSet($sql, $this->db_type, $this->conn);
    return $rs;
}
class RecordSet {
    public $rs;
    public $db_type;
    public $conn;
    public function RecordSet($sql, $db_type, $conn) {
        $this->db_type = $db_type;
        $this->conn = $conn;
        if ($this->db_type == 'sybase') {
            $rsx =@sybase_query($this->sql_escape($sql));
            if (!$rsx) { $this->queryError(sybase_get_last_message(),$sql); }
        } elseif ($this->db_type == 'mssql') {
            $rsx =@mssql_query($this->sql_escape($sql));
            if (!$rsx) { $this->queryError(mssql_get_last_message(),$sql); }
        } elseif ($this->db_type == 'odbc') {
            $rsx =@odbc_exec($this->conn, $this->sql_escape($sql));
            if (!$rsx) { $this->queryError(odbc_errormsg(),$sql); }
        } else {
            $rsx = mysqli_query($this->conn, $this->sql_escape($sql));
            if (!$rsx) { $this->queryError(@mysqli_error($this->conn),$sql); }
        }
        $this->rs = $rsx;
    }
}

问题分析与解决方案

别慌,这个错误和你的INSERT语句本身无关,大概率是**数据库表的触发器(Trigger)**在搞鬼!

你仔细想想,request_boms表上是不是创建了触发器?比如当插入数据时,触发器里执行了包含子查询的SQL操作,而那个子查询返回了多行结果,才导致了这个错误。毕竟你的INSERT语句确实没有子查询,MySQL不可能平白无故抛出这个错误。

另外,也可以检查一下RecordSet类里的sql_escape方法(你代码里调用了它但没贴出来),会不会是这个方法在处理SQL时意外引入了子查询?不过这个可能性比较小,触发器的嫌疑最大。

给你几个验证和解决的步骤:

  1. 直接在数据库客户端执行INSERT语句:
    复制你得到的那条SQL,在phpMyAdmin、Navicat或者MySQL命令行里直接执行:
    INSERT INTO request_boms SET request_list_id = 14, project_version_id = 429, amount = 1, user = 'admin', timestamp = 1607510083
    
    如果同样报错,那100%是表上的触发器有问题。
  2. 查看表的触发器:
    执行这条SQL查看request_boms表的所有触发器:
    SHOW TRIGGERS LIKE 'request_boms';
    
    找到相关触发器后,检查里面的SQL逻辑,看看是不是有子查询返回了多行结果(比如用了=去匹配子查询的结果,但子查询返回了多条记录,这时候应该改用IN,或者调整子查询确保只返回一行)。
  3. 额外提醒:SQL注入风险:
    你的代码用sprintf拼接SQL存在严重的SQL注入风险,建议改用预处理语句(Prepared Statements),比如mysqli的prepare和bind_param方法,既安全又能避免字符串拼接带来的各种奇怪问题。

内容的提问来源于stack exchange,提问作者Hayrettin Basaraner

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 07:47:25