これは、エラーメッセージの品質を向上させるだけでなく、結果セットの処理方法も向上させるアプローチです。
$q["Orders"] = "SELECT * FROM orders WHERE location = 'IN' ORDER BY orderNum DESC LIMIT 20";
$q["Inventory"] = "SELECT * FRO inventory";
if (!$link = mysqli_connect("host", "user", "pass", "db")) {
echo "Failed to connect to MySQL: " , mysqli_connect_error();
} elseif (mysqli_multi_query($link, implode(';', $q))) {
do {
$q_key = key($q); // current query's key name (Orders or Inventory)
if ($result = mysqli_store_result($link)) { // if a result set... SELECTs do
while ($row = mysqli_fetch_assoc($result)) { // if one or more rows, iterate all
$rows[$q_key][] = $row;
}
mysqli_free_result($result);
echo "<div><pre>" . var_export($rows[$q_key], true) . "</pre></div>";
}
} while (next($q) && mysqli_more_results($link) && mysqli_next_result($link));
}
if ($mysqli_error = mysqli_error($link)) { // check & declare variable in same step to avoid duplicate func call
echo "<div style=\"color:red;\">Query Key = " , key($q) , ", Query = " , current($q) , ", Syntax Error = $mysqli_error</div>";
}
最初のクエリでのエラー:最初のクエリが、指定されたデータベースに存在しないテーブルにアクセスしようとすると、次のようになります。ordersXYZ
配列$rows
は存在せず、var_export()
発生せず、次の応答が表示されます。
クエリキー=注文、クエリ= SELECT * FROMordersXYZ WHERE location ='IN' ORDER BY orderNum DESC LIMIT 20、構文エラー=テーブル'[someDB].ordersXYZ'は存在しません
2番目のクエリでのエラー:最初のクエリは成功したが、2番目のクエリが次のような存在しないテーブルにアクセスしようとした場合:inventory2
$rows["Orders"]
目的の行データを保持し、var_export()
'edされ、$row["Inventory"]
存在せず、次の応答が表示されます。
クエリキー=インベントリ、クエリ= SELECT * FROM Inventory2、構文エラー=テーブル'[someDB].inventory2'は存在しません
エラーなし:両方のクエリにエラーがない場合、$rows
配列は目的のデータで埋められ、var_export()
'edされ、エラー応答はありません。に保存されたクエリデータを使用して、および$rows
から必要なものにアクセスできます。$rows["Orders"]
$rows["Inventory"]
注意事項:
変数宣言と条件付きチェックを同時に行っていることに気付くかもしれません。これによりコードがより簡潔になりますが、一部の開発者はこれを避けたいと考えています。
私のアプローチimplode()
では行にセミコロンを使用しているelseif
ため、クエリに末尾のセミコロンを追加しないように注意してください。
このクエリのセットは常に結果セットを返します。これは、すべてがSELECTクエリであるためです。クエリの混合コレクションがある場合は、このリンク( https://stackoverflow.com/a/22469722/2943403affect_rows
)で役立つ情報を見つけることができます。
mysqli_multi_query()
エラーが発生するとすぐにクエリの実行を停止します。「すべての」エラーをキャッチすることを期待している場合は、複数のエラーが発生することはありません。
OPの質問と解決策のように条件付きブレークポイントを記述することはお勧めできません。カスタムブレークポイントは他の状況でも正しく使用できますが、この場合、ブレークポイントはブロックのwhile()
ステートメントの内側に配置する必要があります。do()
ゼロ行を返すクエリでは、エラーメッセージは表示されません。ループが開始されない$rows
ため、サブ配列は作成されません。while()
この関数を使用することにより、各結果セット行の列をカウントするkey()
OPの条件を回避できます。if/elseif
場合によっては、反復ごとに条件を実行するとコストが高くなる可能性があるため、これはより適切な方法です。配列ポインタは、各反復$q
の終わりに内部で進められることに注意してください。do()
これは、phpのマニュアルページにはない追加のテクニックです。key()
意図したとおりに機能します。
そしてもちろん、この<div><pre>var_export()...</pre></div>
行は作業コードから削除できます。これは純粋にデモンストレーション用です。
このコードブロックの後で変数を再利用するクエリをさらに実行する場合は、残りのデータが干渉しないように、使用されているすべての変数を必ずクリアしてください。例:$mysqli_error=null; // clear errors
&reset($q); // reset array pointer
。
あなた自身の裁量でこのやや漠然とした警告に注意してください: http: //php.net/manual/en/mysqli.use-result.php:
クライアント側で多くの処理が実行される場合は、mysqli_use_result()を使用しないでください。これにより、サーバーが拘束され、他のスレッドがデータのフェッチ元のテーブルを更新できなくなります。
- 最後に、セキュリティ上の理由から、クエリやクエリエラー情報を公開しないでください。不吉な人にこの種のフィードバックを見せたくない場合があります。同様に重要なのは、クエリをインジェクションハックから常に保護することです。クエリにユーザー提供のデータが含まれている場合は、で使用する前に、データをフィルタリング/サニタイズして終了する必要があります
mysqli_multi_query()
。実際、ユーザー入力を処理する場合、より高いレベルのセキュリティを実現するために、データベースの相互作用にmysqliまたはpdoのプリペアドステートメントから離れてmysqli_multi_query()
使用することを強くお勧めします。