准备好的语句在 mySQL / PHP 中不起作用

Prepared Statements not working in mySQL / PHP

出于某种原因,我在尝试使用 mysqli

运行 准备好的查询时不断收到此错误

mysqli_stmt::bind_result(): Number of bind variables doesn't match number of fields in prepared statement

这个数据库 class 工作正常,直到我尝试使用 LEFT OUTER JOIN

的查询

不知道有没有人知道为什么?我将 post 下面的查询、架构等。

注意:我在这里看到一个问题,建议我特别拼出我想要 select 的所有字段名称,而不是使用 '*'(star ).涉及很多领域,我花了将近一个小时将它们全部打出来。当我测试时,它没有任何改变。我省略了它并重新使用星号,以防万一有人建议我将它们全部打出来。已经尝试过了。没用。

另外:如果我将它直接放入 phpMyAdmin 中,这个查询工作正常,所以它是一个工作查询。出于某种原因尝试绑定结果时只是抛出错误。即使我删除了多个连接并且只有一个左连接,它仍然会抛出关于参数计数不正确的错误。没看懂。

PHP

的查询输出
SELECT * FROM `SlipMaster` 
left outer join `SlipMain` 
    on `SlipMaster`.`slipCode` = `SlipMain`.`slipCode` 
left outer join `ContractMain` 
    on `SlipMain`.`slipContractId` = `ContractMain`.`id` 
left outer join `ClientMain` 
    on `SlipMain`.`slipClientId` = `ClientMain`.`id` 
left outer join `PaymentMain` 
    on `ContractMain`.`contractPaymentId` = `PaymentMain`.`id` 
left outer join `VesselMain` 
    on `SlipMain`.`slipVesselId` = `VesselMain`.`id` 
WHERE 1 = ?

PHP 使用 MYSQLI 数据库的代码 CLASS

    $from = '
        `SlipMaster` 
        left outer join `SlipMain` 
            on `SlipMaster`.`slipCode` = `SlipMain`.`slipCode` 
        left outer join `ContractMain` 
            on `SlipMain`.`slipContractId` = `ContractMain`.`id` 
        left outer join `ClientMain` 
            on `SlipMain`.`slipClientId` = `ClientMain`.`id` 
        left outer join `PaymentMain` 
            on `ContractMain`.`contractPaymentId` = `PaymentMain`.`id` 
        left outer join `VesselMain` 
            on `SlipMain`.`slipVesselId` = `VesselMain`.`id`';
    $dbi->new_query();
    $dbi->add_param('i', '1');
    $dbi->select($from, '*', '1=?');

PHP MYSQLI 数据库 CLASS

<?php

class mysqliObject {

    public $user = "";
    public $pass = "";          
    public $name = "";
    public $host = "";
    public $_db;
    public $_config;
    public $MYSQLI_LINK = FALSE;
    public $rows = FALSE;
    public $last_error = FALSE;
    public $last_query = FALSE;
    public $result = FALSE;
    public $last_id = FALSE;
    public $paramTypeArray = [];
    public $paramBindArray = [];


    public function __construct() {
    }

    public function __destruct() {

            $this->close();
    }

    public function connect() {

            $this->host = $this->_config->get('DBHOST');
            $this->name = $this->_config->get('DBNAME');
            $this->user = $this->_config->get('DBUSER');
            $this->pass = $this->_config->get('DBPASS');
            $this->MYSQLI_LINK = new mysqli($this->host, $this->user, $this->pass, $this->name);
    }

    public function setDatabase($databaseConnection) {

            $this->_db = $databaseConnection;
    }

    public function setConfig($config) {

            $this->_config = $config;
    }

    public function close() {

            @mysqli_close($this->MYSQLI_LINK);
    }

    public function get_hash($p) {
            return password_hash($p, PASSWORD_BCRYPT, array("cost" => 10)); 
    }

    public function check_password($p, $h) {
            return (password_verify($p, $h)) ? true : false;
    }

    public function get_rndkey($length=32) {

        $random_string="";
        while(strlen($random_string)<$length && $length > 0) {
                $randnum = mt_rand(0,61);
                $random_string .= ($randnum < 10) ?
                        chr($randnum+48) : ($randnum < 36 ? 
                                chr($randnum+55) : $randnum+61);
         }
        return $random_string;
    }

    public function escape($value) {

            return mysqli_real_escape_string($this->MYSQLI_LINK, $value);
    }

    public function get_lastid() {

            return $this->MYSQLI_LINK->insert_id;
    }

    public function new_query() {

            $this->paramTypeArray = Array();    
            $this->paramBindArray = Array();    
    }

    public function add_param($t, $d) {

            $this->paramTypeArray[] = $t;
            $this->paramBindArray[] = $d;
    }


    // Shortcut for Select Method          
    public function s($t,$x, $d, $w) {
            $this->new_query();
            foreach($d as $v) {
                $this->add_param($v['t'], $v['v']);
            }
            return $this->select($t, $x, $w) ? $this->result : false;
    }

    public function select($t, $d, $c) {

            /* Types: s = string, i = integer, d = double,  b = blob */
            $a_params = array();

            $param_type = '';
            $n = count($this->paramTypeArray);
            for($i = 0; $i < $n; $i++) {
                    $param_type .= $this->paramTypeArray[$i];
            }

            $a_params[] = & $param_type;

            for($i = 0; $i < $n; $i++) {
              $a_bind_params[] = $this->paramBindArray[$i];
            }

            for($i = 0; $i < $n; $i++) {
              $a_params[] = & $a_bind_params[$i];
            }

            $q = 'SELECT '.$d.' FROM '.$t.' WHERE '.$c;
            $s = $this->MYSQLI_LINK->prepare($q);

            if($s === false) {
              trigger_error('Wrong SQL: ' . $q . ' Error: ' . $this->MYSQLI_LINK->errno . ' ' . $this->MYSQLI_LINK->error, E_USER_ERROR);
            }

            call_user_func_array(array($s, 'bind_param'), $a_params);

            $s->execute();


            $meta = $s->result_metadata();

            while ($field = $meta->fetch_field()) { 
            $var = $field->name; 
            $$var = null; 
            $fields[$var] = &$$var;
    }


    call_user_func_array(array($s,'bind_result'),$fields);


    $i = 0;
    while ($s->fetch()) {
            $results[$i] = [];

            foreach($fields as $k => $v) {
                $results[$i][$k] = $v;
            }
            $i++;
    }

            $s->close();    

            $this->last_query = $q;


            if (count($results) > 0) {

                    $this->result = $results;
                    return TRUE;
            } else {

                    $this->last_error = mysqli_error($this->MYSQLI_LINK);
                    return FALSE;
            }

            return FALSE;
    }





    public function delete($t, $c) {

        $a_params = array();

        $param_type = '';
        $n = count($this->paramTypeArray);
        for($i = 0; $i < $n; $i++) {
            $param_type .= $this->paramTypeArray[$i];
        }

        $a_params[] = & $param_type;

        for($i = 0; $i < $n; $i++) {
          $a_bind_params[] = $this->paramBindArray[$i];
        }

        for($i = 0; $i < $n; $i++) {
          $a_params[] = & $a_bind_params[$i];
        }

        $q = "delete from ".$t." where ".$c;

        $s = $this->MYSQLI_LINK->prepare($q);

        $this->last_query = $q;

        if($s === false) {
          trigger_error('Wrong SQL: ' . $q . ' Error: ' . $this->MYSQLI_LINK->errno . ' ' . $this->MYSQLI_LINK->error, E_USER_ERROR);
        }

        call_user_func_array(array($s, 'bind_param'), $a_params);

        $s->execute();

        $count = $s->affected_rows;

        $s->close();

        if ($count > 0) {

            $this->rows = $count;
            return TRUE;
        } else {

            $this->last_error = mysqli_error($this->MYSQLI_LINK);
            return FALSE;
        }

    }





    public function insert($t, $d) {


        $a_params = array();

        $param_type = '';
        $n = count($this->paramTypeArray);
        for($i = 0; $i < $n; $i++) {
            $param_type .= $this->paramTypeArray[$i];
        }

        $a_params[] = & $param_type;

        for($i = 0; $i < $n; $i++) {
          $a_bind_params[] = $this->paramBindArray[$i];
        }

        for($i = 0; $i < $n; $i++) {
          $a_params[] = & $a_bind_params[$i];
        }


        $query_cols = 'insert into '.$t.' (';
        $query_vals = 'values (';

        while (list($key, $value) = each($d)) {

            $query_cols .= $value . ', ';

            $query_vals .= '?, ';
        }

        $query_cols = substr($query_cols, 0, strlen($query_cols) - 2);

        $query_vals = substr($query_vals, 0, strlen($query_vals) - 2);

        $q = $query_cols . ') ' . $query_vals . ')';

        $this->last_query = $q;

        $s = $this->MYSQLI_LINK->prepare($q);

        if($s === false) {

          trigger_error('Wrong SQL: ' . $q . ' Error: ' . $this->MYSQLI_LINK->errno . ' ' . $this->MYSQLI_LINK->error, E_USER_ERROR);
        }

        call_user_func_array(array($s, 'bind_param'), $a_params);

        $s->execute();

        $count = $s->affected_rows;
        $this->last_id = $s->insert_id;
        $s->close();

        if ($count > 0) {

            $this->rows = $count;
            return TRUE;
        } else {

            $this->last_error = mysqli_error($this->MYSQLI_LINK);
            return FALSE;
        }

    }


    public function update($t, $d, $c) {

        $a_params = array();

        $param_type = '';
        $n = count($this->paramTypeArray);
        for($i = 0; $i < $n; $i++) {
            $param_type .= $this->paramTypeArray[$i];
        }

        $a_params[] = & $param_type;

        for($i = 0; $i < $n; $i++) {
          $a_bind_params[] = $this->paramBindArray[$i];
        }

        for($i = 0; $i < $n; $i++) {
          $a_params[] = & $a_bind_params[$i];
        }

        $q = 'update ' . $t . ' set ';

        while (list($key, $value) = each($d)) {
                $q .= $value . ' = ?, ';
        }

        //strip comma off end of variable
        $q = substr($q, 0, strlen($q) - 2);

        $q .= ' where ' . $c;

        $this->last_query = $q;

        $s = $this->MYSQLI_LINK->prepare($q);

        if($s === false) {
          trigger_error('Wrong SQL: ' . $q . ' Error: ' . $this->MYSQLI_LINK->errno . ' ' . $this->MYSQLI_LINK->error, E_USER_ERROR);
        }

        call_user_func_array(array($s, 'bind_param'), $a_params);

        $s->execute();

        $count = $s->affected_rows;

        $s->close();

        if ($count > 0) {

            $this->rows = $count;
            return TRUE;
        } else {

            $this->last_error = mysqli_error($this->MYSQLI_LINK);
            return FALSE;
        }
    }

} // End Class

简化架构

注意:如果您需要我 post 更完整的架构,请告诉我。这仅显示正在 link 连接的字段。所有字段都是 INT(255) 唯一的,id 字段是 INT(255) AI PRIMARY

SlipMaster links 通过 slipCodeSlipMain,所有其他 link 外键 小学 id

SlipMaster (id, slipCode)
SlipMain (id, slipCode, slipContractId, slipClientId, slipVesselId)
ContractMain (id, contractPaymentId)
ClientMain (id)
PaymentMain (id)
VesselMain (id)

*所有表中的所有字段JOINing在一起。这包括重复项,例如至少存在两次的 slipCode。

方案 A:拼出您真正想要的字段。这样可以更轻松地计算它们并知道有多少 "bind"。它将明确绑定它们的顺序。

方案 B:不要使用 bind_result;只需将结果提取到数组或散列中即可。

方案C:两者兼顾。 (我更喜欢这个。)

@Notorious,我认为您的问题的答案不是 sql,而是您正在使用的 bind_result() 函数。

进一步解释,bind_result()函数用于将从数据库中检索到的数据分配给变量。所以选择的字段数(从数据库返回)必须等于绑定的结果数。

例如, 如果我从数据库中选择了名字和姓氏字段,我必须使用

bind_result($firstname, $lastname);

正如您所看到的,bind_result() 中的变量数量等于所选字段的数量。

对于您的情况,您正在选择从第一个数据库到第二个到第三个..blablabla 直到最后一个数据库的所有内容。因此,请确保分配给 bind_result() 函数的字段数等于返回的所有字段数。即所有数据库的总列数之和。

所以你需要打很多字,但至少这是最好的。

祝你好运,希望对你有所帮助。