Php 基于PDO的动态列表查询
这个问题我已经讨论了一段时间了,我似乎无法独自解决它。我在PDO和MYSQL中遇到了一些已知的问题/特性,这些问题/特性将我引向下面的代码 我正在数据库中搜索符合多个条件的标记ID。我遇到了一个MYSQL错误,它似乎迫使我在第二次处理之前使用一个临时表来存放我的一些结果。PDO不允许我在第一次执行后引用临时表(我可能做得不对),也不允许我准备多个语句,因此它会引导我为此调用创建一个存储过程。在最近的一些测试之后,我发现了PDO的另一个问题/特性,它不允许我以我想要的方式调用存储过程 以下是SP:Php 基于PDO的动态列表查询,php,mysql,pdo,Php,Mysql,Pdo,这个问题我已经讨论了一段时间了,我似乎无法独自解决它。我在PDO和MYSQL中遇到了一些已知的问题/特性,这些问题/特性将我引向下面的代码 我正在数据库中搜索符合多个条件的标记ID。我遇到了一个MYSQL错误,它似乎迫使我在第二次处理之前使用一个临时表来存放我的一些结果。PDO不允许我在第一次执行后引用临时表(我可能做得不对),也不允许我准备多个语句,因此它会引导我为此调用创建一个存储过程。在最近的一些测试之后,我发现了PDO的另一个问题/特性,它不允许我以我想要的方式调用存储过程 以下是SP:
DELIMITER $$
CREATE PROCEDURE sp_searchPrevArticles(IN tagList VARCHAR(255), IN firstArticle INT(10))
BEGIN
CREATE TEMPORARY TABLE at_results (
id INTEGER(10) NOT NULL AUTO_INCREMENT PRIMARY KEY,
article_id INTEGER(10) NOT NULL,
datetime DATETIME NOT NULL,
common_tags INTEGER NOT NULL)
SELECT at.article_id, art.datetime, Count(at.article_id) AS common_tags
FROM article_tags AS at
INNER JOIN articles AS art ON at.article_id = art.article_id
WHERE at.tag_id IN (tagList)
GROUP BY at.article_id
ORDER BY common_tags DESC, art.datetime DESC;
CREATE TEMPORARY TABLE at_article
SELECT id
FROM at_results
WHERE article_id = firstArticle;
SELECT article_id
FROM at_results, at_article
WHERE at_results.id < at_article.id
ORDER BY at_results.id DESC;
END $$
DELIMITER ;
这给了我一个标签ID的动态列表。对此,我们可以说“4,3,2,1”。当我在没有PDO的情况下运行此SP时,它将返回正确的数据集。每次我用PDO运行它时,它只会给我列表中的第一个标记。在这种情况下,它将只返回“4”的结果
我接到的PDO电话是:
$sql = "CALL sp_searchPrevArticles(:tag_list, :first_article)";
$tag_sth = $this->db->prepare($sql);
$tag_sth->execute(array(':tag_list' => $tag_list, ':first_article' => $first_article));
$tag_sth->setFetchMode(PDO::FETCH_ASSOC);
$data = $tag_sth->fetchAll();
当我继续这样写的时候,我忍不住觉得我让一切对我来说都变得更加困难了。我还在学习,这是迄今为止我提出的最好的解决方案。有人知道如何让它正常工作吗
感谢您的帮助
谢谢 PDO只是不能正确地处理列表,除非它们是静态长度,并且在(?,?,?)中定义为
。我通过以下方式来解决这个问题:
<?php
$list = '1,2,3,4';
$params = array('a', 'b');
$query = "SELECT * FROM TABLE WHERE thing = ? AND other = ? AND more IN (%s)";
$query = sprintf($query, $list);
$rs = $dbh->doQuery($query, $params);
我会把这篇文章贴在这里,供任何想知道答案的人参考。Sammitch的想法非常好,但我就是不能让它与存储过程一起工作。最后,我将变量传递给SQL,并在存储过程中构建完整的查询。我不确定这是否是处理这个问题的最佳方式,但它目前正在发挥作用。我可以担心以后再调整它
DROP PROCEDURE IF EXISTS sp_searchPrevArticles;
DELIMITER $$
CREATE PROCEDURE sp_searchPrevArticles(IN tagList VARCHAR(255), IN firstArticle INT(10))
BEGIN
SET @sql1 = CONCAT('
CREATE TEMPORARY TABLE at_results (
id INTEGER(10) NOT NULL AUTO_INCREMENT PRIMARY KEY,
article_id INTEGER(10) NOT NULL,
datetime DATETIME NOT NULL,
common_tags INTEGER NOT NULL)
SELECT at.article_id, art.datetime, Count(at.article_id) AS common_tags
FROM article_tags AS at
INNER JOIN articles AS art ON at.article_id = art.article_id
WHERE at.tag_id IN (', tagList ,')
GROUP BY at.article_id
ORDER BY common_tags DESC, art.datetime DESC;');
SET @sql2 = CONCAT('
CREATE TEMPORARY TABLE at_article
SELECT id
FROM at_results
WHERE article_id = ', firstArticle, ';');
SET @sql3 = '
SELECT article_id
FROM at_results, at_article
WHERE at_results.id < at_article.id
ORDER BY at_results.id DESC;';
PREPARE stmt FROM @sql1;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
PREPARE stmt FROM @sql2;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
PREPARE stmt FROM @sql3;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END $$
DELIMITER ;
删除程序(如果存在);
分隔符$$
创建过程sp_searchprevactures(在标记列表VARCHAR(255)中,在firstArticle INT(10)中)
开始
SET@sql1=CONCAT('
在_结果处创建临时表(
id整数(10)非空自动递增主键,
第条id整数(10)不为空,
datetime datetime不为空,
公共_标记(整数不为空)
选择at.article\u id、art.datetime、Count(at.article\u id)作为公共\u标记
从第_条标签到
在at.article\u id=art.article\u id上将文章作为艺术进行内部连接
其中at.tag_id位于('标记列表')
分组依据at.article\u id
按常用标签顺序描述,艺术日期时间描述;');
SET@sql2=CONCAT('
在文章中创建临时表
选择id
来自at_的结果
其中,article_id=',firstArticle,';');
SET@sql3=
选择商品标识
来自at_结果,at_文章
其中at_results.id
我仍然需要两个声誉才能开始投票,否则我会投票给你。不小心按了enter键,我无法编辑该评论。谢谢你的回复。我正试图将其合并到我的代码中,但它似乎在做与以前相同的事情。将$sql=“CALL sp_searchprevaricles(%s)”(暂时忘记第二个参数)作为查询应该可以工作,对吗?doQuery是严格必要的吗?我对它不是很熟悉,所以我必须仔细阅读。对不起,doQuery
是我很久以前在PDO上写的一个类的一部分,我只是根据反射写的。它只是将prepare
、execute
和fetch
滚动到一条语句中。再次感谢。事实证明,如果不在SP中拆分存储过程,我无法将一个直接列表传递给存储过程。您的解决方案解决了第一个问题,但现在我正在寻找下一个问题的解决方案。
<?php
$list = array(1,2,3,4); //pretend this is dynamic, and always has at least one member
$params = array('a','b');
$query = "SELECT * FROM TABLE WHERE thing = ? AND other = ? AND more IN (%s)";
$placeholders = '?';
for($i=0; $i<count($list); $i++) {
$placeholders .= ',?';
}
$query = sprintf($query, $placeholders);
$params = array_merge($params, $list);
$rs = $dbh->doQuery($query, $params);
DROP PROCEDURE IF EXISTS sp_searchPrevArticles;
DELIMITER $$
CREATE PROCEDURE sp_searchPrevArticles(IN tagList VARCHAR(255), IN firstArticle INT(10))
BEGIN
SET @sql1 = CONCAT('
CREATE TEMPORARY TABLE at_results (
id INTEGER(10) NOT NULL AUTO_INCREMENT PRIMARY KEY,
article_id INTEGER(10) NOT NULL,
datetime DATETIME NOT NULL,
common_tags INTEGER NOT NULL)
SELECT at.article_id, art.datetime, Count(at.article_id) AS common_tags
FROM article_tags AS at
INNER JOIN articles AS art ON at.article_id = art.article_id
WHERE at.tag_id IN (', tagList ,')
GROUP BY at.article_id
ORDER BY common_tags DESC, art.datetime DESC;');
SET @sql2 = CONCAT('
CREATE TEMPORARY TABLE at_article
SELECT id
FROM at_results
WHERE article_id = ', firstArticle, ';');
SET @sql3 = '
SELECT article_id
FROM at_results, at_article
WHERE at_results.id < at_article.id
ORDER BY at_results.id DESC;';
PREPARE stmt FROM @sql1;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
PREPARE stmt FROM @sql2;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
PREPARE stmt FROM @sql3;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END $$
DELIMITER ;