23

WHERE IN(?)値の配列を句にバインドする必要があります。どうやってやるの?

これは機能します:

$mysqli = new mysqli("localhost", "root", "root", "db");
if(!$mysqli || $mysqli->connect_errno)
{
    return;
}
$query_str= "SELECT name FROM table WHERE city IN ('Nashville','Knoxville')";
$query_prepared = $mysqli->stmt_init();
if($query_prepared && $query_prepared->prepare($query_str))
{       
    $query_prepared->execute();

しかし、これは次のようなbind_paramで作業することはできません:

$query_str= "SELECT name FROM table WHERE city IN (?)";
$query_prepared = $mysqli->stmt_init();
if($query_prepared && $query_prepared->prepare($query_str))
{       
    $cities= explode(",", $_GET['cities']);
    $str_get_cities=  "'".implode("','", $get_cities)."'"; // This equals 'Nashville','Knoxville'

    $query_prepared->bind_param("s", $cities);
    $query_prepared->execute();

私は何を間違っていますか?

も試しましcall_user_func_arrayたが、正しい構文を取得できないようです。

4

7 に答える 7

49

このタスクは少し複雑ですが実行可能です。私の記事Mysqli prepare statement with multiple values for IN clauseから説明を引用します。

  • まず、?配列内の要素と同じ数のマークを持つ文字列を作成する必要があります。このstr_repeat()ために、目的に非常に便利な関数を使用します。
  • 次に、疑問符で区切られたこの文字列をクエリに追加する必要があります。変数ですが、この場合は定数値しか含まれていないので安全です
  • このクエリは、他のクエリと同じように準備する必要があります
  • 次に、bind_param() で使用するタイプの文字列を作成する必要があります。通常、バインドされた変数に異なる型を使用する理由はないことに注意してください - mysql は喜んでそれらをすべて文字列として受け入れます。特殊なケースもありますが、非常にまれです。日常的に使用する場合は、常にシンプルに保ち、すべてに「s」を使用できます。str_repeat()再び助けになります。
  • 次に、配列の値をステートメントにバインドする必要があります。残念ながら、この のように単一の変数として記述することはできません。$stmt->bind_param("s", $array)ではスカラー変数のみが許可されbind_param()ます。幸いなことに、必要なことを正確に実行する引数アンパック演算子があります。値の配列を、あたかも個別の変数のセットであるかのように関数に送信します!
  • 残りは通常どおりです。クエリを実行し、結果を取得してデータをフェッチします。

したがって、正しいコード例は次のようになります

$array = ['Nashville','Knoxville']; // our array
$in    = str_repeat('?,', count($array) - 1) . '?'; // placeholders
$sql   = "SELECT name FROM table WHERE city IN ($in)"; // sql
$stmt  = $mysqli->prepare($sql); // prepare
$types = str_repeat('s', count($array)); //types
$stmt->bind_param($types, ...$array); // bind array at once
$stmt->execute();
$result = $stmt->get_result(); // get the mysqli result
$data = $result->fetch_all(MYSQLI_ASSOC); // fetch the data   

このコードはかなり大きいですが、これまでにこのトピックで提供された他の妥当なソリューションと比べて比較にならないほど小さいです。

于 2019-10-12T15:28:57.393 に答える
13

2 つの変数を 1 つのquestion mark!にバインドすることはできません。

バインドする変数ごとに、1 つ必要ですquestion mark

「bind_param」は、各変数が要件に一致するかどうかをチェックします。その後、文字列値が引用符で囲まれます。

これは機能しません。

"SELECT name FROM table WHERE city IN (?)"; ( becomes too )
$q_prepared->bind_param("s", $cities);
"SELECT name FROM table WHERE city IN ('city1,city2,city3,city4')";

でなければなりません。

"SELECT name FROM table WHERE city IN (?,?,?,?)"; ( becomes too )
$q_prepared->bind_param("ssss", $city1,$city2,$city3,$city4);
"SELECT name FROM table WHERE city IN ('city1','city2','city3','city4')";

$query_prepared->bind_param文字列パラメーターを 1 つずつ引用符で囲みます。
また、変数の数と文字列型の長さは、ステートメントのパラメーターと一致する必要があります。

$query_str= "SELECT name FROM table WHERE city IN ('Nashville','Knoxville')";

となります

$query_str= "SELECT name FROM table WHERE city IN (?,?)";

bind_paramでなければならない

bind_param("ss",$arg1,$arg2)

これとともに

$query_str= "SELECT name FROM table WHERE city IN (?)";

そしてbind_param_

bind_param("s",$cities)

あなたが得る

$query_str= "SELECT name FROM table WHERE city IN ('Nashville,Knoxville')";

そのため、配列は機能しません。
この事実に対する唯一の解決策は、call_user_func_array

ステートメントを初期化する場合、以下は不要です

$query_prepared = $mysqli->stmt_init();
if($query_prepared && $query_prepared->prepare($query_str)) {

正解です

$query_prepared = $mysqli->stmt_init();
if($query_prepared->prepare($query_str)) {

使用したくない場合call_user_func_array
で、引数の数が少ない
場合は、次のコードで実行できます。

[...]
$cities= explode(",", $_GET['cities']);
if (count($cities)>3) { echo "too many arguments"; }
else
{ 
$count = count($cities); 
$SetIn = "(";
  for($i = 0; $i < $count; ++$i) {    
      $code.='s';
      if ($i>0) {$SetIn.=",?";} else {$SetIn.="?";}
  }
$SetIn.=")";
$query_str= "SELECT name FROM table WHERE city IN ".$SetIn;
// with 2 arguments $query_str will look like
// SELECT name FROM table WHERE city IN (?,?)
$query_prepared = $mysqli->stmt_init();
if($query_prepared->prepare($query_str))
  {       
    if ($count==1) { $query_prepared->bind_param($code, $cities[0]);}
    if ($count==2) { $query_prepared->bind_param($code, $cities[0],$cities[1]);}
    if ($count==3) { $query_prepared->bind_param($code, $cities[0],$cities[1],$cities[2]);
    // with 2 arguments $query_prepared->bind_param() will look like
    // $query_prepared->bind_param("ss",$cities[0],$cities[1])      
  }    

    $query_prepared->execute();
  } 
 [...]
 }

到達するために試してみることをお勧めしますcall_user_func_array

mysqli-stmt.bind-paramの解決策を探しますnick9v

于 2013-06-21T05:34:35.073 に答える
4

次のように call_user_func_array を使用します。

$stmt = $mysqli->prepare("INSERT INTO t_file_result VALUES(?,?,?,?)");

$id = '1111';
$type = 2;
$result = 1;
$path = '/root';

$param = array('siis', &$id, &$type, &$result, &$path);
call_user_func_array(array($stmt, 'bind_param'), $param);

$stmt->execute();

printf("%d row inserted. \n", $stmt->effected_rows);
$stmt->close;
于 2016-05-09T09:33:47.957 に答える
0

私もこれで問題を抱えていましevalたが、ほとんどの人が使用していることを知る前に動作しましたcall_user_func_array

$fields = array('model','title','price'); // fields in WHERE clause
$values = array( // type and value for each field
    array('s','ABCD-1001'),
    array('s','[CD] Test Title'),
    array('d','16.00')
);
$sql = "SELECT * FROM products_info WHERE "; // start of query
foreach ($fields as $current){ // build where clause from fields
    $sql .= '`' . $current . '` = ? AND ';
}
$sql = rtrim($sql,'AND '); // remove last AND 
$stmt = $db->prepare($sql);
$types = ''; $vals = '';
foreach ($values as $index => $current_val){ // build type string and parameters
    $types .= $current_val[0];
    $vals .= '$values[' . $index . '][1],';
}
$vals = rtrim($vals,','); // remove last comma
$sql_stmt = '$stmt->bind_param("' . $types . '",' . $vals . ');'; // put bind_param line together
eval($sql_stmt); // execute bind_param
$stmt->execute();
$stmt->bind_result($col1,$col2,$col3,$col4,$col5,$col6); // this could probably also be done dynamically in the same way
while ($stmt->fetch()){
    printf("%s %s %s %s %s %s\n", $col1,$col2,$col3,$col4,$col5,$col6);
}
于 2014-02-02T11:00:40.737 に答える
0

私が行った方法:すべての個別の疑問符とタイプ文字列を使用してクエリを準備します。

$cities = array('Nashville','Knoxville');
$dibs = '';
$query = "SELECT name FROM table WHERE city IN (";
$marks = array();

foreach ($cities as $k => $city) {
    // i,s,b,d type based on the variables to bind.
    $dibs .= 's';
    array_push($marks, '?');
}

$query .= implode(',', $marks) .')';

接続。

$mysql = new mysqli($host, $user, $pass, $dbname);
$statement =
    $mysql->prepare($query)
OR  die(sprintf(
        'Query error (%s) %s', $mysql->errno, $mysql->error
    ))
;

次に、配列をバインドするために「...」トークン/省略記号 (ドキュメント) を使用します。

if ($statement) {
    $statement->bind_param($dibs, ...$cities);
    $statement->execute();

    $statement->close();
}
$mysql->close();

エスケープするためにバインディングの目的を少し無効にすることは知っています(ただし、少なくとも整数のリスト、つまりIDではうまく機能します)。このアプローチを改善する方法を見つけた場合は、自由に編集/コメントしてください。

于 2019-06-25T21:44:04.977 に答える