web-dev-qa-db-ja.com

プリペアドステートメントでSELECTクエリを実行するのに問題がある

プリペアドステートメントでのSELECTの使用に関して、さまざまな例を実行しましたが、何も返されません。 [〜#〜] edit [〜#〜]コードを次のように少し変更しました:

$date1 = 2012-01-01;
$date2 = 2012-01-31;
$sql_con = new mysqli('db', 'username', 'password', 'database');

if($stmt = $sql_con->prepare("SELECT eventLogID FROM Country WHERE countryCode=? AND date BETWEEN ? AND ?")){

   $stmt->bind_param("sss", $country_code, $date1,$date2); 

    $stmt->execute();

  $i=0;
  while ($stmt->fetch()){
  $stmt->bind_result($row[$i]);
  $i++;
  }

  $stmt->close();
$sql_con->close();

これで、最初のエントリを除くすべての必要なエントリが$ row []に追加されます。最初のエントリが追加されないのはなぜですか?前もって感謝します!

9
Glenncito

[〜#〜]編集[〜#〜]2015年7月(質問は元の回答以降編集されていますが、基本的な原則は同じです)

Never_SELECT *_実稼働環境では、奇妙で予測不可能で、一見無関係な方法であなたを噛むために戻ってくるだけです。必要な列を指定することにより、列の順序、データ型、制約、およびその他のあらゆる種類の要素が長期的に問題を引き起こさないようにします。

この回答はまだほとんど有効なので、ここではそのままにしておきますが、主なポイントは次のとおりです。PDOを使用すると、必要な処理の98%が実行され、よりクリーンで簡潔なAPIが使用されます。同じバックエンド。より複雑なRDBMS固有のAPIが必要な場合は、発生している問題と、代わりにmysqliなどが必要な理由をすでに理解しているはずです。


_SELECT *_は、MySQLiで準備されたステートメントではうまく機能しません。これは、私がお勧めする主な理由の1つです [〜#〜] pdo [〜#〜] 代わりに-それと、値ではなく変数参照をパラメーターにバインドするというばかげた要件です。

_$stmt->bind_result($row);
_

これは、結果rowを変数にバインドするのではなく、単一の列をバインドするだけです。そして、あなたは_SELECT *_を使用したので、それはあなたが望むことをしません。

PDOではなくMySQLiを使用したい場合(私が言うように、これをお勧めします)、コメントに_SELECT *_する方法の良い例がいくつかあります this one on bind_result()マニュアルページ。

または、取得する列を指定することもできます。

_$sql_con = new mysqli('db', 'username', 'password', 'database');

if($stmt = $sql_con->prepare("SELECT name, countryCode FROM Country WHERE countryCode = ?")) {

   $stmt->bind_param("s", $country_code); 
   $stmt->execute(); 
   $stmt->bind_result($name, $countryCode);

   while ($stmt->fetch()) {
     // Because $name and $countryCode are passed by reference, their value
     // changes on every iteration to reflect the current row
     echo "<pre>";
     echo "name: $name\n";
     echo "countryCode: $countryCode\n";
     echo "</pre>";
   }

   $stmt->close();
_

[〜#〜]編集[〜#〜]新しいコードに基づいて、次のようにする必要があります。

_// $date1 will be int(2010), $date2 will be int(1980) because you didn't
// quote the strings!
//$date1 = 2012-01-01;
//$date2 = 2012-01-31;

// Connect to DB
$sql_con = new mysqli('db', 'username', 'password', 'database');

// Check for connection errors here!

// The query we want to execute
$sql = "
  SELECT eventLogID
  FROM Country
  WHERE countryCode = ?
  AND date BETWEEN ? AND ?
";

// Attempt to prepare the query
if ($stmt = $sql_con->prepare($sql)) {

  // Pass the parameters
  $date1 = '2012-01-01';
  $date2 = '2012-01-31';
  $stmt->bind_param("sss", $country_code, $date1, $date2); 

  // Execute the query
  $stmt->execute();
  if (!$stmt->errno) {
    // Handle error here
  }

  // Pass a variable to hold the result
  // Remember you are binding a *column*, not a row
  $stmt->bind_result($eventLogID);

  // Loop the results and fetch into an array
  $logIds = array();
  while ($stmt->fetch()) {
    $logIds[] = $eventLogID;
  }

  // Tidy up
  $stmt->close();
  $sql_con->close();

  // Do something with the results
  print_r($logIds);

} else {
  // Handle error here
}
_
21
DaveRandom

Bind_results()の列に次のようにバインドする必要があると思います

/* prepare statement */
if ($stmt = $mysqli->prepare("SELECT Code, Name FROM Country ORDER BY Name LIMIT 5")) {
$stmt->execute();

/* bind variables to prepared statement */
$stmt->bind_result($col1, $col2);

/* fetch values */
while ($stmt->fetch()) {
    printf("%s %s\n", $col1, $col2);
}

ここで、$ col1と$ col2は、CountryテーブルのCode列とName列にバインドされます。

(SELECTの*の代わりに列名を使用してください)

詳細参照: http://php.net/manual/en/mysqli-stmt.bind-result.php

3
Makesh

最も単純な1行の予想されるクエリを超えてmysqliの「bind_result」のファンではありません。

行全体を単一の配列アイテムに詰め込むには、次の方法を使用する方が適切です。

$stmt->execute();
$result = $stmt->get_result();
while ($data = $result->fetch_assoc())
    {
        $retvar[] = $data;
    }
$stmt->close();

または

while ($data = $result->fetch_row())

フィールド名が必要ない/必要ない場合。

1
Roger Krueger