PHP MySQL准备语句加入错误

时间:2011-08-06 10:24:45

标签: php mysql join mysqli prepared-statement

更新:请参阅下文;我删除了所有抽象并创建了一个普通的PHP脚本,但仍然得到相同的错误。有关详细信息,请参阅下面的“其他更新”...

原帖:我有一个通过数据库抽象层正确形成的查询。查询如下:

SELECT 5c9_dpd_users.id, 5c9_dpd_users.username, 5c9_dpd_users.cms_usergroup_id,  
5c9_dpd_usergroups_cms.usergroup_name, 5c9_dpd_users.email FROM 5c9_dpd_users LEFT JOIN
5c9_dpd_usergroups_cms ON 5c9_dpd_usergroups_cms.id = 5c9_dpd_users.cms_usergroup_id 
ORDER BY username asc

如果我生成相同的查询但是将其作为预准备语句运行,该语句参数化WHERE子句的第二个操作数,如下所示,我得到的结果不正确。我确信声明本身是正确的,我正在运行MySQLi准备。声明函数按正确的顺序排列。准备好的语句查询如下:

SELECT 5c9_dpd_users.id, 5c9_dpd_users.username, 5c9_dpd_users.cms_usergroup_id, 
5c9_dpd_usergroups_cms.usergroup_name, 5c9_dpd_users.email FROM 5c9_dpd_users LEFT JOIN 
5c9_dpd_usergroups_cms ON 5c9_dpd_usergroups_cms.id = ? ORDER BY username asc

此查询似乎将参数化的5c9_dpd_users.cms_usergroup_id转换为“5”,因为运行查询会从SELECT子句中检索正确的列,但会为所有usergroup_name返回相同的5c9_dpd_usergroups_cms.id结果 - 此用户组名称与5 call_user_func_array()的结果的用户组名称匹配。

我是动态绑定参数(?)。在这个例子中,我告诉它将i参数绑定为5c9_dpd_users.cms_usergroup_id。我想也许这可能会因为某种原因将5转换为s,但我尝试了所有其他三种数据类型(bd和{{1}没有运气。

注意:我已经多次使用我的数据库抽象层没有问题,尽管这是它运行连接的第一个实例(它最近才开发)。重申一下,如果查询没有参数化,查询将通过PHP和MySQL控制台返回正确的结果,但如果通过PHP预处理语句函数给出?,则结果不正确,如上所述。

如果有人可以提供帮助,我将非常感激。我一直在谷歌上搜索这个问题的帮助,我找不到任何类似的实例记录在任何地方。谢谢。

编辑(提供PHP代码):

$stmt->select_prep(array('users.id', 'users.username', 'users.cms_usergroup_id', 'usergroups_cms.usergroup_name', 'users.email'), array('users'));
$stmt->left_join_prep('usergroups_cms');
$stmt->on_prep('usergroups_cms.id', '=', 'users.cms_usergroup_id', 'i');

$stmt->order($column, $asc_desc);
$stmt->execute_prep();

现在执行查询,我所要做的就是调用$ stmt-> fetch_prep(),这是一种基本上检索结果集的包装方法。此客户端代码生成的查询在上面给出了第二个 - 参数化 - 我给出的查询作为示例。

我在$ stmt-> execute_prep()方法中打印了一些调试代码,并且绑定到查询的参数正确显示为:

Array
(
  [0] => i
  [1] => 5c9_dpd_users.cms_usergroup_id
)

这意味着它将一个参数(键1)绑定为int(键0)。我也尝试将它绑定为字符串,double和blob,没有效果。

另一个更新:

我创建了一个测试脚本来完全删除我的数据库抽象层,结果是一样的:没有返回cms用户组名。这是脚本:

<?php
$mysqli = new mysqli('localhost', 'root', '', 'frame');

$q = "SELECT ac9_dpd_users.id, ac9_dpd_users.username, ac9_dpd_users.cms_usergroup_id, 
ac9_dpd_usergroups_cms.usergroup_name, ac9_dpd_users.email 
FROM ac9_dpd_users 
LEFT JOIN ac9_dpd_usergroups_cms 
ON ac9_dpd_usergroups_cms.id = ? 
ORDER BY username asc";

$stmt = $mysqli->prepare($q);
$stmt->bind_param('i', $param);
$param = 'ac9_dpd_users.cms_usergroup_id';
$stmt->execute();

$stmt->bind_result($a, $b, $c, $d, $e);

while ($stmt->fetch()) {
    echo "id: $a <br>un: $b <br>id: $c <br>cms name: $d <br>email: $e<br><br>";
}

$stmt->close();
unset($mysqli);
?>

输出:

id: 7 
un: ADD 
id: 1 
cms name: 
email: test@test.com

id: 1 
un: New User 
id: 2 
cms name: 
email: test@test.com

1 个答案:

答案 0 :(得分:1)

也许我只是有点挑剔但我不会用数字开始一个表/字段名称。使用字母或用反引号(`)包围这些奇怪的名称。它应该工作。

修改(根据您的问题更改)

您编辑的脚本的某些位置会发出警告:

     ...
     ON ac9_dpd_usergroups_cms.id = ? 
     ...
     $stmt->bind_param('i', $param);
     $param = 'ac9_dpd_users.cms_usergroup_id';

如php手册中所述,mysqli::prepare接受where子句中的参数,但不允许 更改查询的列名称。

此外,对字符串进行整数绑定应该在将值插入准备好的查询之前将值转换为数字,并且$ params应该转换为0。

在执行后发出sqlstate语句来检查查询的内容:

...
$stmt->execute();
$sqlError = $stmt->sqlstate();
if($sqlError != '00000') die($sqlError);
...

可能的解决方案:

<?php
$mysqli = new mysqli('localhost', 'root', '', 'frame');

$q = "SELECT ac9_dpd_users.id, ac9_dpd_users.username, ac9_dpd_users.cms_usergroup_id, 
ac9_dpd_usergroups_cms.usergroup_name, ac9_dpd_users.email 
FROM ac9_dpd_users 
LEFT JOIN ac9_dpd_usergroups_cms 
ON ac9_dpd_usergroups_cms.id = ac9_dpd_users.cms_usergroup_id 
ORDER BY username asc";

$stmt = $mysqli->prepare($q);
$stmt->execute();

$stmt->bind_result($a, $b, $c, $d, $e);

while ($stmt->fetch()) {
    echo "id: $a <br>un: $b <br>id: $c <br>cms name: $d <br>email: $e<br><br>";
}

$stmt->close();
unset($mysqli);
?>