准备好的语句不适用于mySQL / PHP

时间:2015-07-02 11:16:20

标签: php mysql prepared-statement

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

运行准备好的查询时一直收到此错误
  

mysqli_stmt :: bind_result():绑定变量数不匹配   准备好的陈述中的字段数

这个db类工作正常,直到我尝试使用LEFT OUTER JOIN

的查询

我想知道是否有人知道为什么?我将在下面发布查询,架构等。

注意:我在这里看到一个问题,建议我专门拼出我想要选择的所有字段名称,而不是使用'*'(星号)。涉及很多领域,我花了将近一个小时的时间将它们全部输入。当我测试时,它没有改变任何东西。我已经省略了它并返回使用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 = ?

使用MYSQLI DB CLASS的PHP代码

    $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 DB 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

简化架构

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

SlipMaster通过SlipMain链接到slipCode,所有其他链接都是外键  到小学id

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

2 个答案:

答案 0 :(得分:2)

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

计划A:拼出你真正想要的字段。这样可以更容易地计算它们并知道要“绑定”多少。并且它将清楚地说明绑定它们的顺序。

B计划:不要使用bind_result;只需将结果提取到数组或散列中。

计划C:两者都做。 (我更喜欢这个。)

答案 1 :(得分:2)

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

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

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

bind_result($firstname, $lastname);

因此,您可以看到bind_result()中的变量数等于所选字段的数量。

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

所以你打算做很多打字,但至少要做到最好。

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