2014-01-21 69 views
1

我花了整晚的時間研究並試圖找出我的搜索查詢出了什麼問題。我使用聯合查詢和分頁進行一些通配符搜索。PDO - SQLSTATE [HY093]:帶有UNION查詢的參數號無效

$current_page = 0; 

$search1 = $search; 
$search2 = $search."%"; 
$search3 = "%".$search."%"; 

$pdo = DB::connection()->getPdo(); 

$stmt = $pdo->prepare(' 
    SELECT id, desc FROM table WHERE desc LIKE :search1 LIMIT :skip, 15 
    UNION 
    SELECT id, desc FROM table WHERE desc LIKE :search2 LIMIT :skip, 15 
    UNION 
    SELECT id, desc FROM table WHERE desc LIKE :search3 LIMIT :skip, 15 
'); 

$stmt->bindParam(':search1', $search1); 
$stmt->bindParam(':search2', $search2); 
$stmt->bindParam(':search3', $search3); 
$stmt->bindParam(':skip', $current_page, PDO::PARAM_INT); 

$stmt->execute(); 

$result = $stmt->fetchAll(PDO::FETCH_ASSOC); 

第一個查詢(沒有聯合)工作正常,或者如果我刪除:skip參數,它也可以正常工作。

任何想法有什麼不對?

+1

'desc'是保留字(如'table'但我懷疑這就是你用什麼作爲表名,對嗎?*眨眼*)。它需要用反引號包裹。 http://dev.mysql.com/doc/refman/5.5/en/reserved-words.html --- **等待答案**堆在此評論後...(*我討厭如果我這樣做的話,就會陷入潛在的蠕蟲病毒庫中。*) –

+0

爲什麼要使用佔位符的偏移量,這是默認值。 – Mihai

+0

你不能只是做'desc LIKE:search1 OR desc LIKE:search2 OR desc LIKE:search3'? – Class

回答

6

在PDO使用命名參數,你不能使用同一名稱超過一次,除非你這樣做:除非你這樣做:

$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, true); 

但是,如果你這樣做,:skip的值將插入到查詢中作爲帶引號的字符串,這在LIMIT上下文中無效。換句話說如下:

LIMIT '0', 15 

導致語法錯誤,因爲LIMIT只需要真正的整數作爲它的參數。

更多的例子和說明,請參閱我的回答Parametrized PDO query and LIMIT clause - not working

所以,你的選擇是增加一個單獨的參數爲:skip每次出現:

$stmt = $pdo->prepare(' 
    SELECT id, desc FROM table WHERE desc LIKE :search1 LIMIT :skip1, 15 
    UNION 
    SELECT id, desc FROM table WHERE desc LIKE :search2 LIMIT :skip2, 15 
    UNION 
    SELECT id, desc FROM table WHERE desc LIKE :search3 LIMIT :skip3, 15 
'); 

$stmt->bindParam(':search1', $search1); 
$stmt->bindParam(':search2', $search2); 
$stmt->bindParam(':search3', $search3); 
$stmt->bindParam(':skip1', $current_page, PDO::PARAM_INT); 
$stmt->bindParam(':skip2', $current_page, PDO::PARAM_INT); 
$stmt->bindParam(':skip3', $current_page, PDO::PARAM_INT); 

否則插值值到查詢自己,沒有引用整數。

但我同意@Class的評論,你根本不需要做UNION。如果沒有別的,'%search%'適用於其他兩種模式:'search%''%search'。你不必搜索全部三個。

+0

感謝您的好解釋,它完美的工作! (由於上述原因我需要工會。) – orszaczky

0

將每個SELECT放在括號內。

documentation

通過或LIMIT應用於爲了將個人選擇,將子句括起來,括號內的SELECT:

$stmt = $pdo->prepare(' 
    (SELECT id, desc FROM table WHERE desc LIKE :search1 LIMIT :skip, 15) 
    UNION 
    (SELECT id, desc FROM table WHERE desc LIKE :search2 LIMIT :skip, 15) 
    UNION 
    (SELECT id, desc FROM table WHERE desc LIKE :search3 LIMIT :skip, 15) 
'); 
+0

我試過這個,但它給了我同樣的錯誤 – orszaczky

0

就像更新一樣,如果有人在這裏試圖實現類似的搜索,並通過相關性返回結果,上面的原始查詢將複製一些結果,並且每個選擇的限制都會跳過一些結果。

在一些測試下面的查詢似乎做如預期的那樣工作:

$current_page = ($_GET['page'] - 1) * 15; 

$search1 = $search; 
$search2 = $search."%"; 
$search3 = "%".$search."%"; 

$pdo = DB::connection()->getPdo(); 

$stmt = $pdo->prepare(' 
    SELECT id, desc FROM table WHERE desc LIKE :search1 
    UNION 
    SELECT id, desc FROM table WHERE desc LIKE :search2 AND desc NOT LIKE :search1a 
    UNION 
    SELECT id, desc FROM table WHERE desc LIKE :search3 AND desc NOT LIKE :search2a 
    LIMIT :skip, 15 
'); 

$stmt->bindParam(':search1', $search1); 
$stmt->bindParam(':search1a', $search1); 
$stmt->bindParam(':search2', $search2); 
$stmt->bindParam(':search2a', $search2); 
$stmt->bindParam(':search3', $search3); 
$stmt->bindParam(':skip', $current_page, PDO::PARAM_INT); 

$stmt->execute(); 

$result = $stmt->fetchAll(PDO::FETCH_ASSOC); 
相關問題