【发布时间】:2015-09-19 21:28:41
【问题描述】:
由于某种原因,我在尝试使用 mysqli 运行准备好的查询时不断收到此错误
mysqli_stmt::bind_result(): 绑定变量数不匹配 准备好的语句中的字段数
这个 db 类工作正常,直到我尝试使用带有 LEFT OUTER JOIN 的查询
我想知道是否有人知道为什么?我将在下面发布查询、架构等。
注意:我在这里看到一个问题,建议我专门拼出我想要选择的所有字段名称,而不是使用 '*'(星号)。涉及很多领域,我花了将近一个小时将它们全部输入。当我测试时,它没有改变任何东西。我省略了这一点并返回使用星号,以防万一有人建议我将它们全部输入。已经试过了。没用。
另外:如果我将它直接放入 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 类的 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 数据库类
<?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 通过slipCode 链接到SlipMain,所有其他链接外键
到主要id
SlipMaster (id, slipCode)
SlipMain (id, slipCode, slipContractId, slipClientId, slipVesselId)
ContractMain (id, contractPaymentId)
ClientMain (id)
PaymentMain (id)
VesselMain (id)
【问题讨论】:
-
那里有一个条件子句,但为了测试我只是更改为 1 = 1 所以毫无疑问 where 子句是否会导致问题。尽管从错误中看起来如此,但我相信该错误是由其他原因引起的。也许与 DB 类有关的问题作为查询对我来说似乎很简单。
-
要解析的代码太多了。但是为了帮助您指出正确的方向,这与
*无关,并且它怀疑 JOINS 应该受到指责。错误是您尝试绑定的参数数量不等于准备好的语句中?s 的数量。尝试打印出您的 $a_params 数组以检查您要绑定的内容。 -
只有一个?如查询所示标记。如果我删除连接,则查询有效。 @dan08
-
你应该调试你的db类的select方法。特别是这一行: call_user_func_array(array($s, 'bind_param'), $a_params);验证您当时的假设。
-
天哪,我误读了错误,它是
bind_result而不是bind_param。所以错误就在这里:call_user_func_array(array($s,'bind_result'),$fields);。我会在 Msql 控制台中运行查询以查看列是什么,以及print_r($fields);并确保它们像您想的那样匹配。也许 JOIN 正在添加您的$meta->fetch_field()函数未捕获的字段。拼出 SELECT 中的列将有助于避免这个问题。
标签: php mysql mysqli prepared-statement