1

私はこれを少しの間バッティングしてきましたが、自分で解決できないようです。PDO と MYSQL の既知の問題/機能に遭遇したため、以下のコードにたどり着きました。

複数の条件に一致するタグ ID をデータベースで検索しています。MYSQL のバグに遭遇したため、2 回目の処理を行う前に結果の一部を格納するために一時テーブルを使用する必要があったようです。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 ;

正しく機能しないパラメーターは tagList です。でtagListを作成します

foreach ($tag_ids as $tag) {
    $tag_list = ($tag_list . $tag . ",");
}
$tag_list = rtrim($tag_list, ',');

これにより、タグ ID の動的リストが得られます。この場合、「4,3,2,1」と言えます。この SP を PDO なしで実行すると、適切なデータ セットが返されます。これを 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();

このように書き続けていると、自分がすべてを難しくしていると思わずにはいられません。私はまだ学んでいますが、これは私がこれまでに思いついた最良の解決策です。これを適切に機能させる方法を知っている人はいますか?

どんな助けでも大歓迎です。

ありがとう!

4

2 に答える 2

3

リストが静的な長さであり、 のように定義されていない限り、PDO はリストを適切に処理しませんIN(?,?,?,?)。私はそれを回避します:

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

それはお粗末ですが、動的な長さのリストに関して PHP からの実際の解決策をまだ見ていません。

これを書くための、より醜い、しかしより準拠した方法を考えました:

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

大まかで一般的ですが、アイデアはわかります。すべてを完全にパラメータ化することに真剣に取り組んでいない限り、私は最初のスニペットを好みます。

于 2012-12-05T22:08:57.270 に答える
0

これに対する答えを探している他の人のために、これをここに投稿します。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 ;
于 2012-12-07T17:38:45.637 に答える