2010-09-13 60 views
13

假設我們有一個查詢:一份聲明中`WHERE。在(..)`查詢和排序 - 與MySQL

SELECT * FROM somewhere WHERE `id` IN(1,5,18,25) ORDER BY `name`; 

和一組ID獲取:$ids = array(1,5,18,25)

隨着準備語句是adviced準備一個語句,並調用它多次:

$stmt = $mysqli->prepare('SELECT * FROM somewhere WHERE `id`=?;'); 
foreach ($ids as $id){ 
    $stmt->bind_params('i', $id); 
    $stmt->exec(); 
    } 

但現在我必須對結果進行排序手動。我有什麼好的選擇嗎?

+0

根據您所提供的我鏈接認爲準備語句的原因是需要在一個查詢中更新其不支持多個更新。而你是SELECTing,所以你的第一個查詢就足夠了。 – 2010-09-13 18:30:35

+0

我確信在這種情況下準備好的陳述並不好。唯一不錯的解決方案是「向上查詢一個查詢」,並將該數組的ID排序在那裏,而不是在這裏。 – kolypto 2010-09-14 01:13:29

回答

19

你可以這樣來做:

$ids = array(1,5,18,25); 

// creates a string containing ?,?,? 
$clause = implode(',', array_fill(0, count($ids), '?')); 


$stmt = $mysqli->prepare('SELECT * FROM somewhere WHERE `id` IN (' . $clause . ') ORDER BY `name`;'); 

call_user_func_array(array($stmt, 'bind_param'), $ids); 
$stmt->execute(); 

// loop through results 

使用這個你調用每個ID bind_param和你排序由mysql完成。

+1

是的,但壞事是查詢不能重用,所以根本沒有必要準備:) – kolypto 2010-09-13 18:26:49

+1

@o_O Tync:數據庫訪問越少越好。歡迎您繼續使用PreparedStatement約束,但如果您需要對同一個表運行10/20/50/100/1000 +查詢,則不會擴展。 – 2010-09-13 18:30:14

+1

爲這個聲明創建一個視圖不是更好,因爲它不能被重複使用嗎? – 2010-09-13 18:35:31

0

不,如果您要使用ORDER BY子句從數據庫中提取某些記錄,則不推薦這麼做。

1

另一種方法是在結果對象上使用PHP usort函數,但這是「手動」。

看到這個: Sort Object in PHP

3

我加入了一個最終緩慢&醜陋的解決方案其仍然使用準備好的發言的數組項目的任何號碼:3個語句是很普遍的任何情況下和隨處重用。

  1. CREATE TEMPORARY TABLE IDS ( ID INT);
  2. INSERT INTO IDS VALUES(?);這將插入你的ID
  3. SELECT ID FROM IDS從其它表LEFT JOIN .... ;利用數據進行排序ids列表
  4. SELECT ID FROM IDS ;選擇一切返回

否則,您將不得不使用IN (?,?,?,....或手動排序行。最好的想法是使用簡單的MySQL查詢,或者嘗試獲取已經按照您喜歡的方式排序的ID列表。

0

您是否考慮過使用JOIN和WHERE子句重寫原始查詢以獲取需要的IDS以避免需要WHERE IN子句?我帶着同樣的問題來到這裏,在回顧可能的解決方案後,我意識到INNER JOIN是我的解決方案。

+0

這就是內部邏輯:應用程序需要通過ID從外部提供N個用戶。很高興你的情況變得不那麼具體:) – kolypto 2014-01-07 04:22:31

5

我相信這是最簡單的可能的答案:

$ids = [1,2,3,4,5]; 
$pdos = $pdo->prepare("SELECT * FROM somwhere WHERE id IN (:" 
     . implode(',:', array_keys($ids)) . ") ORDER BY id"); 

foreach ($ids as $k => $id) { 
    $pdos->bindValue(":". $k, $id); 
} 

$pdos->execute(); 
$results = $pdos->fetchAll(); 

只要你的ID的數組不包含非法字符鍵或按鍵,它西港島線工作。

1

有同樣的問題,另外7年前的@sled答案,這裏是未做call_user_func_array(array($stmt, 'bind_param'), $ids);一步的可能性,但只有一次打電話bind_params:

$ids = array(1,5,18,25); 

// creates a string containing ?,?,? 
$bindClause = implode(',', array_fill(0, count($ids), '?')); 
//create a string for the bind param just containing the right amount of iii 
$bindString = str_repeat('i', count($ids)); 

$stmt = $mysqli->prepare('SELECT * FROM somewhere WHERE `id` IN (' . $bindClause . ') ORDER BY `name`;'); 

$stmt->bind_params($bindString, ...$ids); 
$stmt->execute();