0

我发现自己在 PDO 中处于一个非常奇怪的境地。从 PhP 调用时不想执行查询,但从 HeidiSQL 调用时它会执行。

错误在标题中。

来自语句 debugDumpParams 的 SQL 查询:

SELECT s_id AS id,
 s_title AS title,
 genre.g_name AS genreName,
 accounts.ac_public_name AS producerName,
 s_price AS price, 
 DATE_FORMAT(s_last_modified_date, '%d/%m/%Y %H:%i:%s') AS lastModifiedDate, 
 DATE_FORMAT(s_added_date, '%d/%m/%Y %H:%i:%s') AS addedDate,
 s_downloads AS downloads,
 s_sales AS sales,
 s_rating AS rating, 
 s_status AS STATUS
FROM song
JOIN accounts ON accounts.ac_id = song.s_producer
JOIN genre ON genre.g_id = song.s_genre
WHERE 1=1 AND genre.g_id = '1'
ORDER BY s_status ASC, s_added_date DESC
LIMIT 0, 5;

接下来是我在查询字符串中添加genre.g_id = :id 的部分

 if(isset($filterData["genreId"]) && $filterData["genreId"] !== ""){
    $queryString .= " AND genre.g_id = :genreId";
 }

在我绑定它的地方

 if(isset($filterData["genreId"]) && $filterData["genreId"] !== ""){
    $genreParam = $filterData["genreId"];
    $stmt->bindParam('genreId', $genreParam);
 }

在这两种情况下都设置了 $filterData["genreId"] 并且它有一个值,所以 if 没有问题。如果 $filterData["genreId"] 为空或未设置,则查询没有问题。

并且错误: SQLSTATE[42S22]: Column not found: 1054 Unknown column \'genre.g_id\' in \'where clause\'

但是等等,还有更多。如果我放genre.g_id2 而不是genre.g_id,它将如下所示:

 if(isset($filterData["genreId"]) && $filterData["genreId"] !== ""){
    $queryString .= " AND genre.g_id2 = :genreId";
 }

现在它甚至达不到 $stmt->debugDumpParams(); 它给出的只是这个错误: SQLSTATE[42S22]: Column not found: 1054 Unknown column \'genre.g_id2\' in \'where clause\ ,没有像以前那样的查询。

表中存在 100% 列。此查询的类似问题:

SELECT s_id AS id,
 s_title AS title,
 genre.g_name AS genreName,
 accounts.ac_public_name AS producerName,
 s_price AS price, 
 DATE_FORMAT(s_last_modified_date, '%d/%m/%Y %H:%i:%s') AS lastModifiedDate, 
 DATE_FORMAT(s_added_date, '%d/%m/%Y %H:%i:%s') AS addedDate,
 s_downloads AS downloads,
 s_sales AS sales,
 s_rating AS rating, 
 s_status AS STATUS
FROM song
JOIN accounts ON accounts.ac_id = song.s_producer
JOIN genre ON genre.g_id = song.s_genre
WHERE 1=1 AND accounts.ac_id = '999999'
ORDER BY s_status ASC, s_added_date DESC
LIMIT 0, 5;

似乎问题仅出在与表songJOIN 一起使用的表中的列上。

下一个查询完美运行。

SELECT s_id AS id,
 s_title AS title,
 genre.g_name AS genreName,
 accounts.ac_public_name AS producerName,
 s_price AS price, 
 DATE_FORMAT(s_last_modified_date, '%d/%m/%Y %H:%i:%s') AS lastModifiedDate, 
 DATE_FORMAT(s_added_date, '%d/%m/%Y %H:%i:%s') AS addedDate,
 s_downloads AS downloads,
 s_sales AS sales,
 s_rating AS rating, 
 s_status AS STATUS
FROM song
JOIN accounts ON accounts.ac_id = song.s_producer
JOIN genre ON genre.g_id = song.s_genre
WHERE 1=1 AND s_status = '0'
ORDER BY s_status ASC, s_added_date DESC
LIMIT 0, 5;

2天,没有解决方案。我发现的大多数解决方案都是再次检查该列是否确实存在:| 有没有人对这个特定问题有更好的解决方案?

目标是选择 g_id 与我传递给它的值相等的数据。

我如何创建查询字符串:

 $queryString = "SELECT s_id as id,
                            s_title as title,
                            genre.g_name as genreName,
                            accounts.ac_public_name as producerName,
                            s_price as price, 
                            DATE_FORMAT(s_last_modified_date, '%d/%m/%Y %H:%i:%s') as lastModifiedDate,
                            DATE_FORMAT(s_added_date, '%d/%m/%Y %H:%i:%s')  as addedDate,
                            s_downloads as downloads,
                            s_sales as sales,
                            s_rating as rating,     
                            s_status as status
                            FROM song 
                            JOIN accounts on accounts.ac_id = song.s_producer
                            JOIN genre on genre.g_id = song.s_genre
                            WHERE 1=1 ";

然后在一个函数中我添加这个

 if(isset($filterData["genreId"]) && $filterData["genreId"] !== ""){
    $queryString .= " AND genre.g_id = :genreId";
 }

然后我这样做

$queryString .= " ORDER BY s_status asc, s_added_date desc";
$queryString .= " LIMIT :offset, :limit;";

最后

  $stmt = $dbConnector->getConnection()->prepare($queryString);

这是与问题相关的部分。我不能发布整个功能,它真的很长。

这用于根据某些输入或输入组合搜索数据。整个 DAO 类真的很大 :)

操作系统:Windows 10,PhP 版本:7.2.19,Apache 版本:2.4.35,MariaDB 版本:10.4 Heidi SQL:10.2.0.5599

再编辑一个:

如果我在第一次声明它时在 queryString 中添加列:

$queryString = "SELECT s_id as id,
                            s_title as title,
                            genre.g_name as genreName,
                            accounts.ac_public_name as producerName,
                            s_price as price, 
                            DATE_FORMAT(s_last_modified_date, '%d/%m/%Y %H:%i:%s') as lastModifiedDate,
                            DATE_FORMAT(s_added_date, '%d/%m/%Y %H:%i:%s')  as addedDate,
                            s_downloads as downloads,
                            s_sales as sales,
                            s_rating as rating,     
                            s_status as status
                            FROM song 
                            JOIN accounts on accounts.ac_id = song.s_producer
                            JOIN genre on genre.g_id = song.s_genre
                            WHERE 1=1 AND genre.g_id = :genreId";
        $queryString = $this->filterDataQuery($queryString, $filterData, "songs");
        $queryString .= " ORDER BY s_status asc, s_added_date desc";
        $queryString .= " LIMIT :offset, :limit;";
        $stmt = $dbConnector->getConnection()->prepare($queryString);
        $genreParam = $filterData["genreId"];
        $stmt->bindParam(':genreId', $genreParam);

而不是在 $this->filterDataQuery($queryString, $filterData, "songs"); 当我基于选定的过滤器构建 queryString 时,它工作得很好。这是现在从浏览器控制台中选择的:

SELECT s_id AS id,

 s_title AS title,

 genre.g_name AS genreName,

 accounts.ac_public_name AS producerName,

 s_price AS price, DATE_FORMAT(s_last_modified_date, '%d/%m/%Y %H:%i:%s') AS lastModifiedDate, DATE_FORMAT(s_added_date, '%d/%m/%Y %H:%i:%s') AS addedDate,

 s_downloads AS downloads,

 s_sales AS sales,

 s_rating AS rating, 

 s_status AS STATUS
FROM song
JOIN accounts ON accounts.ac_id = song.s_producer
JOIN genre ON genre.g_id = song.s_genre
WHERE 1=1 AND genre.g_id = '1'
ORDER BY s_status ASC, s_added_date DESC
LIMIT 0, 5;

这个和第一个不一样吗?因为它是。我瞎了?

4

2 回答 2

0

首先,我没有将 $stmt 变量传递给 filterDataQuery。我将它传递给 bindParams。在完成 filterDataQuery 并添加 order by 和 limit 的字符串之后调用 bindParams 函数。

我真的要感谢你,Piemol,你试图帮助我。

在我大学的一位教授建议我这样做后,我检查了 Maria DB 日志,我在那里发现了问题

在同一个控制器中,我调用了两个 DAO 方法,一个接一个,一个带来数据,另一个进行计数。

  $responseMessage = json_encode(AdminDAO::getInstance()->getFilteredSongsList($message));
  $count = AdminDAO::getInstance()->getFilteredSongsListItemsCount($message); // this one was the problem

问题不在于获取数据的那个,而是我发布的那个。问题在于进行计数的人。我没有在那里添加连接:| . 在那里没有任何迹象表明错误来自什么方法,所以我专注于错误的方法(日志中显示的那个)。如果我像在 Java 中那样使用记录器,就不会发生这样的事情。

以下是来自 MariaDB 日志文件的查询:https ://www.heypasteit.com/clip/0IUPWG 第一个是失败的,第二个是有效的。

我非常想念 Java 中的 log4j。

感谢所有试图帮助我的人。

对于那些有这种奇怪问题的人,检查日志,放置回显,不要专注于你在 AJAX 响应日志中看到的第一件事。

于 2020-05-21T20:22:23.767 回答
0

在重读了你的第一篇文章数十次并在本地测试了各种正常的东西而没有遇到同样的错误之后,我认为$stmt里面的变量filterDataQuery()与这里发布的查询完全不同。它只是不包括genre错误消息中显示的表格。如果您没有使用该功能,请查看倒数第二个代码块,一切正常(如果我理解正确的话)。

同样根据显示的代码,我不明白您将如何调用filterDataQuery()以向查询字符串添加条件,并将参数直接绑定到稍后准备的语句对象,因此在那里不可用(或者不是您期望的那个)。

为了证明我的理论我的完整测试代码,仍然使用这个 db-fiddle

ini_set('display_errors', 1);
error_reporting(E_ALL);

$DB_USER = '*****';
$DB_PASS = '*****';
$db = new PDO('mysql:host=localhost;dbname=testing.project', $DB_USER, $DB_PASS);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);

$select = 'SELECT s_id AS id,
 s_title AS title,
 genre.g_name AS genreName,
 accounts.ac_public_name AS producerName,
 s_price AS price, 
 DATE_FORMAT(s_last_modified_date, "%d/%m/%Y %H:%i:%s") AS lastModifiedDate, 
 DATE_FORMAT(s_added_date, "%d/%m/%Y %H:%i:%s") AS addedDate,
 s_downloads AS downloads,
 s_sales AS sales,
 s_rating AS rating, 
 s_status AS STATUS
FROM song
JOIN accounts ON accounts.ac_id = song.s_producer
JOIN genre ON genre.g_id = song.s_genre';
$where = ' WHERE genre.g_id = :genreId';
$order = ' ORDER BY s_status ASC, s_added_date DESC';
$limit = ' LIMIT 0, 5';

// No problemo:
$sql = $select . $where . $order . $limit;
$stmt = $db->prepare($sql);
$genreId = 1;
$stmt->bindParam(':genreId', $genreId);
$stmt->execute();

// Trigger error column not found, $stmt containing an unexpected query:
$select = 'SELECT * FROM `song`';
$sql = $select . $where . $order . $limit;
$stmt = $db->prepare($sql);
$genreId = 1;
$stmt->bindParam(':genreId', $genreId);
$stmt->execute();
于 2020-05-21T13:21:25.007 回答