使用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));
有没有人拿出一个更优雅的解决方案呢?
Answer 1:
这是一处占位符落在他们的脸上。 减去自动转义,他们几乎真的只是一个字符串替换operationt内部,也就是说如果你有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
越预期isntead
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)";
然后绑定你的参数是平常。
Answer 2:
作为危险品说,你需要建立的参数,然后通过调用它们传递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;
}
Answer 3:
在你可以“建立” 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);
注:这是未经测试
Answer 4:
在通常是缓慢和没有准备发言友好。 更好的解决方案是建立将在IN和使用JOIN来达到相同的效果的项目表。
Answer 5:
有没有人拿出一个更优雅的解决方案呢?
当然。 我是。
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版本)这个代码是整齐和可读性 。 这是很重要的事情。 你可以告诉这个代码做了一年后也通过了什么呢。
文章来源: mySQL bind_param with IN(?)