mySQL bind_param с IN (?)

Используя bind_param во всех моих запросах, теперь я хочу использовать IN(?) Где количество элементов в списке может меняться.

Функция SQLout, которую я использую здесь, в основном выполняет $sql_db->prepare , ->bind_param , ->execute() , ->store_result() , ->bind_result

 // the code below does not work as the query only matches on element 'a': $locations = ('a','b','c','d','e'); SQLout ("SELECT Name FROM Users WHERE Locations IN (?)", array('s', $locations), array(&$usrName)); // the code below does work as a brute-force method, // but is not a viable solution as I can't anticipate the number of elements in $locations going forward: SQLout ("SELECT Name FROM Users WHERE Locations IN (?,?,?,?,?)", array('sssss', $locations[0],$locations[1],$locations[2],$locations[3],$locations[4]), array(&$usrName)); 

Кто-нибудь придумал более элегантное решение?

Solutions Collecting From Web of "mySQL bind_param с IN (?)"

Это одно место, заполнившее их лица. Минус автоэксплуатации – это почти буквально операция замены строк внутри, что означает, что если у вас есть WHERE x IN (?) И перейдите в 1,2,3,4 , вы получите эквивалент

 WHERE x IN ('1,2,3,4') // note, it's a string, not individual comma-separated ints 

логически эквивалентно

 WHERE x = '1,2,3,4' // again, just a string 

является более ожидаемым

 WHERE (x = 1) or (x = 2) or (x = 3) or (x = 4) 

Единственное практическое решение – создать собственный список ? , например:

 $placeholders = implode(array_fill(0, count($values), '?')); $sql = "SELECT ... WHERE x IN ($placeholders)"; 

а затем привязать параметры, как правило.

Как сказал Хазмат, вам нужно создать параметры, а затем передать их, вызвав call_user_func_array в подготовленном операторе, но немного ближе к рабочему коду, чем его пример 🙂

 //In the calling code $queryString = "SELECT Name FROM Users WHERE Locations IN ("; $queryString .= getWhereIn($locations); $queryString .= " )"; $parametersArray = array(); foreach($locations as $location){ $parameter = array(); $parameter[0] = 's'; //It's a string $parameter[1] = $location; $parametersArray[] = $parameter; } //This is a function in a class that wraps around the class mysqli_statement function bindParameterArray($parameterArray){ $typesString = ''; $parameterValuesArray = array(); foreach($parameterArray as $parameterAndType){ $typesString .= $parameterAndType[0]; $parameterValuesArray[] = $parameterAndType[1]; } $finalParamArray = array($typesString); $finalParamArray = array_merge($finalParamArray, $parametersArray); call_user_func_array(array($this->statement, "bind_param"), $finalParamArray); } function getWhereIn($inArray){ $string = ""; $separator = ""; for($x=0 ; $x<count($inArray) ; $x++){ $string .= $separator."?"; $separator = ", "; } return $string; } 

Вы можете «построить» в разделе IN , прежде чем подготовить / связать его.

 $sql = 'SELECT Name FROM Users WHERE Locations IN (' . implode(array_fill(0, count($locations), '?')) . ')'; 

Затем вы можете использовать call_user_func_array для привязки параметров, не зная сколько их там.

 // Parameters for SQLOut $params = array( # The SQL Query $sql, # The params for bind_param array(str_repeat('s', count($locations))), # The params for bind_result array(&$usrName) ); // Add the locations into the parameter list foreach($locations as &$loc){ // not sure if this is needed, but bind_param // expects its parameters to be references $params[1][] = &$loc; } // Call your function call_user_func_array('SQLout', $params); 

Примечание. Это не проверено

IN обычно медленный и не подготовленный к заявлению дружественный. Лучшее решение – построить таблицу элементов, которые будут в IN, и использовать JOIN, чтобы получить тот же эффект.

Кто-нибудь придумал более элегантное решение?

Конечно. Я.

Mysqli практически непригодным для использования с подготовленными заявлениями, особенно с такими сложными случаями.
Таким образом, лучше избавиться от подготовленных заявлений и реализовать свои собственные заполнители с поддержкой всех случаев реальной жизни, с которыми может встретиться разработчик.

Таким образом, у safeMysql есть решение, которое вы ищете (а также решения для дюжины других головных болей).

В вашем конкретном случае это будет так же просто, как эта единственная строка кода

 // the code works all right: $locations=array('a','b','c','d','e'); $usrName=$db->getCol("SELECT Name FROM Users WHERE Locations IN (?a)",$locations); 

в отличие от уродливых кодов вы можете играть с некоторыми функциями PHP и API (и по-прежнему получать тревожные предупреждения зависит от версии PHP, которую вы используете в данный момент), этот код является аккуратным и читаемым . Это важно. Вы можете сказать, что делает этот код даже после года.