2012-12-05 34 views
1

我一直在打這個這個,我似乎無法自己解決。我遇到了已知的問題/功能與PDO和MYSQL,導致我到下面的代碼。用PDO動態列表查詢

我在數據庫中搜索符合多個條件的標記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 ; 

是無法正常工作的參數標記列表。我創建tagList與

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

這給了我一個標籤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(); 

正如我繼續寫他們這樣,我不禁想,我正在爲自己的一切都變得更加困難。我仍然在學習,這是迄今爲止我提出的最佳解決方案。任何人都有關於如何正確運作的想法?

任何幫助表示讚賞。

謝謝!

回答

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

這是雜牌組裝電腦-Y,但我還沒有看到從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); 

它的粗糙和一般,但你的想法。除非你真的真的致力於參數化絕對我喜歡的第一個片段。

+0

我仍然需要兩個聲望來啓動upvoting,否則我會upvote你。 – Alduron

+0

意外命中輸入,我不能編輯該評論。感謝您的答覆。我正在試圖將其納入我的代碼中,但似乎與以前一樣。使$ sql =「CALL sp_searchPrevArticles(%s)」(現在忘記第二個參數)作爲查詢應該工作,對吧? doQuery是否嚴格必要?我對它不是很熟悉,所以我不得不閱讀它。 – Alduron

+0

對不起,'doQuery'是我在PDO幾年前寫的類中的一部分,我只是通過反射來寫它。它只是把'prepare','execute'和'fetch'放到一個語句中。 – Sammitch

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 ;