繁体   English   中英

PHP MySQL预准备语句联接错误

[英]PHP MySQL Prepared Statement Join Error

更新:请参见下文; 我删除了所有抽象并创建了一个简单的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.id5

我正在动态绑定参数( call_user_func_array() )。 在这种情况下,我告诉它绑定? 参数作为i 我以为是由于某种原因,这可能使它将5c9_dpd_users.cms_usergroup_id转换为5 ,但是我尝试了所有其他三种数据类型( sbd ),但没有成功。

注意:尽管这是它运行连接的第一个实例(它是最近才开发的),但我已经多次使用我的数据库抽象层了。 重申一下,如果未参数化查询,但给定一个? ,则查询会通过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

等等

也许我有点挑剔,但我不会以数字开头的表/字段名称。 使用字母或将这些怪异的名称用反引号( ` )引起来。 它应该工作。

编辑(根据您的问题更改)

您编辑过的脚本的某些地方会向我发出警报:

     ...
     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);
?>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM