web-dev-qa-db-ja.com

「WHERE column =?」のMySQLでの疑問符の意味は何ですか?

私はいくつかのコードを分析していますが、これに遭遇しました、

$sql = 'SELECT page.*, author.name AS author, updator.name AS updator '
     . 'FROM '.TABLE_PREFIX.'page AS page '
     . 'LEFT JOIN '.TABLE_PREFIX.'user AS author ON author.id = page.created_by_id '
     . 'LEFT JOIN '.TABLE_PREFIX.'user AS updator ON updator.id = page.updated_by_id '
     . 'WHERE slug = ? AND parent_id = ? AND (status_id='.Page::STATUS_REVIEWED.' OR status_id='.Page::STATUS_PUBLISHED.' OR status_id='.Page::STATUS_HIDDEN.')';

「?」って何だろうWHEREステートメントで行います。何らかのパラメーターホルダーですか?

39
Levi

準備された文は「?」を使用しますMySQLで、パラメーターをステートメントにバインドできるようにします。適切に使用すれば、SQLインジェクションに対してより安全であると高く評価されます。また、リクエストは一度コンパイルするだけで再利用できるため、より高速なSQLクエリが可能になります。

36
Jayrox

疑問符は、後で置き換えられるパラメーターを表します。パラメーター化されたクエリを使用する方が、パラメーターをクエリに直接埋め込むよりも安全です。

SQL Serverはこれをパラメーター化クエリと呼び、Oracleはバインド変数と呼びます。

使用法は、クエリを実行する言語によって異なります。

PHPからの使用例を次に示します。

仮定して $mysqliはデータベース接続であり、peopleは4列のテーブルです。

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

$stmt->bind_param('sssd', $firstName, $lastName, $email, $age);

'sssd'は、残りのパラメータを識別するフラグです。sは文字列を表し、dは数字を表します。

28
Steve Stedman

?はMySQLで特別な意味を持ちませんWHERE =ステートメント

PHP stdlibやRailsのようなWebフレームワークなど、いくつかの外部インターフェースに対して特別な意味を持つだけです。

?は、次の構文エラーです。

CREATE TABLE t (s CHAR(1));
SELECT * FROM t WHERE s = ?;

引用符で囲まれていないため、および:

INSERT INTO t VALUES ('a');
INSERT INTO t VALUES ("?");
SELECT * FROM t WHERE s = '?';

それは返します:

s
?

したがって、明らかに特別な意味はありません。

レールの例

Railsでは、疑問符は、ライブラリのプログラミング言語(Ruby)の変数で指定された引数に置き換えられます。例:

Table.where("column = ?", "value")

また、バグやSQLインジェクションを回避するために引数を自動的に引用し、次のようなステートメントを生成します。

SELECT * FROM Table WHERE column = 'value';

次のような場合、クォートは私たちを救うでしょう:

Table.where("column = ?", "; INJECTION")

MySQL 5.0準備済みステートメント

MySQL 5.0は、Webフレームワークの疑問符と同様のセマンティクスを持つ 準備済みステートメント機能 を追加しました。

ドキュメントの例:

PREPARE stmt1 FROM 'SELECT SQRT(POW(?,2) + POW(?,2)) AS hypotenuse';
SET @a = 3;
SET @b = 4;
EXECUTE stmt1 USING @a, @b;

出力:

hypotenuse
5

また、これらは期待どおりに特殊文字をエスケープします。

PREPARE stmt1 FROM 'SELECT ? AS s';
SET @a = "'";
EXECUTE stmt1 USING @a;

出力:

s
'

これらは準備された声明であり、準備された声明は2つの主要な利点を提供します:

クエリは1回だけ解析(または準備)する必要がありますが、同じまたは異なるパラメーターを使用して複数回実行できます。クエリが準備されると、データベースはクエリの実行計画を分析、コンパイル、最適化します。複雑なクエリの場合、このプロセスは時間がかかり、同じパラメータを異なるパラメータで何度も繰り返す必要がある場合、アプリケーションの速度が著しく低下します。準備されたステートメントを使用することにより、アプリケーションは分析/コンパイル/最適化サイクルを繰り返すことを避けます。これは、準備されたステートメントが使用するリソースが少ないため、実行が高速になることを意味します。

準備済みステートメントのパラメーターを引用する必要はありません。ドライバーはこれを自動的に処理します。アプリケーションが準備済みステートメントのみを使用する場合、開発者はSQLインジェクションが発生しないことを確認できます(ただし、クエリの他の部分がエスケープされていない入力で構築されている場合、SQLインジェクションは引き続き可能です)。

http://php.net/manual/en/pdo.prepared-statements.php

1
Raheel