7

これが1000回聞かれたことは知っていますが、どういうわけか私は壁に頭をぶつけ続けています。

これは機能します:

$sql = 'SELECT a.eventCode, a.eventTime, a.teamCode, a.playerCode, b.lastName, b.firstName, b.number, a.xCoord, a.yCoord, a.id ';
$sql = $sql . 'FROM events a, players b ';
$sql = $sql . 'WHERE a.regGUID in ( ' . $regGUID . ' ) and ';
$sql = $sql . 'a.playerCode=b.playerCode and a.gameCode = "' . $game . '" order by a.eventTime desc, a.actionCode asc'; 
$stmt = $db->prepare($sql);
$results = $stmt->execute();

これはしません:

$sql = 'SELECT a.eventCode, a.eventTime, a.teamCode, a.playerCode, b.lastName, b.firstName, b.number, a.xCoord, a.yCoord, a.id ';
$sql = $sql . 'FROM events a, players b ';
$sql = $sql . 'WHERE a.regGUID in ( :regGUID ) and ';
$sql = $sql . 'a.playerCode=b.playerCode and a.gameCode = :game order by a.eventTime desc, a.actionCode asc'; 
$stmt = $db->prepare($sql);
$stmt->bindValue(':regGUID', $regGUID, PDO::PARAM_STR);
$stmt->bindValue(':game', $game, PDO::PARAM_STR);
$results = $stmt->execute();

私は何が欠けていますか?ありがとう

4

4 に答える 4

5

問題はここにあります:

$sql = $sql . 'WHERE a.regGUID in ( :regGUID ) and ';
$stmt->bindValue(':regGUID', $regGUID, PDO::PARAM_STR);

$ regGUIDは、引用符で囲まれた文字列のコンマ区切りのリストであると想定しています。

各クエリパラメータは、単一のスカラー値のみを受け入れます。値のリストではありません。

したがって、2つの選択肢があります。

  1. 他のスカラー値にパラメーターを使用する場合でも、$regGUID文字列の補間を続行します。ただし、SQLインジェクションを回避するように注意する必要があるため、$regGUID文字列を正しく作成する必要があります。文字列全体に対してPDO::quote()を呼び出すことはできません。これにより、UUIDとコンマを含む単一引用符で囲まれた文字列になります。各UUID文字列がエスケープされ、個別に引用符で囲まれていることを確認してから、リストを一緒に内挿し、IN句に補間する必要があります。

    $regGUIDs = explode(',', $regGUID);
    $regGUIDs = array_map(function ($g) { return $db->quote($g); }, $regGUIDs);
    $regGUID = implode(',', $regGUIDs);
    $sql = $sql . 'WHERE a.regGUID in (' . $regGUID . ') and ';
    
  2. explode()$ regGUIDを配列に追加し、配列内の要素ごとに1つのクエリパラメーターを追加します。クエリパラメータプレースホルダーの動的リストを補間します。

    $regGUIDs = explode(',', $regGUID);
    $params = array_fill(1, count($regGUIDs), '?');
    $sql = $sql . ' WHERE a.regGUID in ( ' . implode(',', $params) . ' ) and ';
    

配列のループでbindValue()を使用できますが、他のパラメーターも名前ではなく位置でバインドする必要があることに注意してください。PDOには、同じクエリで2つの異なるスタイルのパラメータを混在させようとすると満足できないバグがあります。

bindValue()を使用する代わりに、パラメーター値の配列をPDOStatement :: execute()に渡すだけです。これは、はるかに簡単です。

$paramValues = $regGUIDs;
$paramValues[] = $game;
$results = $stmt->execute($paramValues);
于 2013-01-19T17:18:49.163 に答える
2

これは確かに1000回尋ねられました。

プリペアドステートメントは、SQLクエリの任意の部分ではなく、スカラー値のみを受け入れることができます。

挿入する必要のあるアイテムと同じ数のプレースホルダーを使用してIN()ステートメントを作成し、それらを1つずつバインドする必要があります。

このタスクを簡単にするために、いくつかのヘルパー関数を使用できます。

たとえば、 SafeMysqlライブラリを使用すると、このコードは次のように記述できます。

$sql  = 'SELECT * FROM events a, players b WHERE regGUID in (?a) and';
$sql .= ' a.playerCode=b.playerCode and a.gameCode = ?s';
$sql .= ' order by a.eventTime desc, a.actionCode asc'; 
$results = $db->getAll($sql,$regGUID,$game);

$regGUID文字列ではなく配列である必要があり、$resultsそれ以上の処理を行わずに、要求されたすべてのデータがすでに含まれていることに注意してください。

于 2013-01-19T17:04:50.390 に答える
1

内容は$regGUID?句を使用しているのでin、コンマ区切りのリストだと思います。

変数をパラメーターにバインドすることは、その文字列をクエリに代入することとは異なります。これは、実際のP​​HP変数の使用方法をMySQLに指示するようなものです。したがって'1,2,3'、クエリパラメータのような文字列をバインドすると、1つの文字列のままになり、数値のリストとして再解釈されません。

したがって、$regGUIDがのようなものである場合"'AAA1', 'BBB2'"、最初のクエリは次のようになります。

... WHERE a.regGUID in ( 'AAA1', 'BBB2' ) ...

しかし、2番目のクエリはもっと​​似ています

... WHERE a.regGUID in ( '\'AAA1\', \'BBB2\'' ) ...

これは言うのと同じです

... WHERE a.regGUID = '\'AAA1\', \'BBB2\'' ...
于 2013-01-19T17:06:06.600 に答える
1

他の人は状態を持っているので、単一のスカラー値のみをプレースホルダーにバインドできます。つまり、これは、INステートメントの各値に実際にプレースホルダーが必要であることを意味します。私は通常、次のようなことをします。ただし、私は決して使用しないことに注意してくださいbindValue。Mysqliのような参照である必要があることに関するルールがある場合は、以下を変更する必要があります。

$regGUIDPlaceholders = array();

// prepare the placeholders
// assume regGUID is an array - if its a string then explode on whatever to make it an array
foreach($regGUID as $k => $v) {
   $placeholder = ':regGUID' . $k;
   $regGUIDPlaceholders[$key] = $value;
}

// prepare the IN statememnt
$in = sprintf('IN (%s)', implode(',', array_keys($regGUIDPlaceholders)));

$sql = 'SELECT a.eventCode, a.eventTime, a.teamCode, a.playerCode, b.lastName, b.firstName, b.number, a.xCoord, a.yCoord, a.id ';
$sql = $sql . 'FROM events a, players b ';

// USE the IN statement dynamically prepared above
$sql = $sql . 'WHERE a.regGUID '. $in . ' and ';

$sql = $sql . 'a.playerCode=b.playerCode and a.gameCode = :game order by a.eventTime desc, a.actionCode asc'; 

$stmt = $db->prepare($sql);

// bind each GUID to its placeholder
foreach($regGUIDPlaceholders as $placeholder => $value) {
   $stmt->bindValue($placeholder, $value, PDO::PARAM_STR);
}

$stmt->bindValue(':game', $game, PDO::PARAM_STR);
$results = $stmt->execute();
于 2013-01-19T17:18:43.353 に答える