私は、クエリを書くための最良の方法を学ぼうとしています。また、一貫性を保つことの重要性も理解しています。今までは、シングルクォート、ダブルクォート、バックティックを何の気なしに使っていました。
例を挙げます。
$query = 'INSERT INTO table (id, col1, col2) VALUES (NULL, val1, val2)';
また、上記の例では、table
、col1
、val1
などが変数になっている場合も考えられます。
これは何か基準があるのでしょうか?あなたはどうしますか?
ここで似たような質問の回答を20分ほど読んでいますが、決定的な答えはないようです。
バックティックはテーブルやカラムの識別子に使用されますが、識別子が MySQL reserved keyword である場合や、識別子にホワイトスペース文字や限定されたセットを超えた文字が含まれている場合にのみ必要となります(下記参照)。 予約されたキーワードをカラムやテーブルの識別子として使用することは、可能な限り避けることが推奨され、クオートの問題を回避することができます。
VALUES()`リストのような文字列値にはシングルクォートを使用してください。 二重引用符はMySQLでも文字列値に対してサポートされていますが、一重引用符のほうが他のRDBMSでは広く受け入れられているので、二重引用符の代わりに一重引用符を使うのが良い習慣です。
MySQL は、DATE
および DATETIME
リテラル値が、'2001-01-01 00:00:00'
のような文字列としてシングルクォートされることも期待しています。詳細については、日付と時刻のリテラルのドキュメントを参照してください。特に、日付文字列のセグメントデリミタとしてハイフン -
を使用する方法などがあります。
この例では、PHP の文字列を二重引用符で囲み、値 'val1', 'val2'
には一重引用符を使用しています。 NULL` は MySQL のキーワードであり、特殊な(非)値であるため、引用符は使用しません。
これらのテーブルやカラムの識別子はいずれも予約語ではなく、またクォートが必要な文字を使用していませんが、とりあえずバックティックでクォートしています(これについては後で詳しく説明します...)。
RDBMS に固有の関数 (たとえば MySQL の NOW()
) はクォートしてはいけませんが、その引数はすでに述べたような文字列や識別子のクォート規則に従います。
バックティック (`) テーブル&カラム ───────┬─────┬──┬────┬──┬────┬──┬───────┐ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ $query = "INSERT INTO `table` (`id`, `col1`, `col2`, `date`, `updated`) VALUES (NULL, 'val1', 'val2', '2001-01-01', NOW())"; ↑↑↑↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑↑↑↑↑ 引用されていないキーワード ─────┴┴┘ │ │ │ │ │││││ 一重引用符で囲まれた(')文字列 ───────────┴────┴─┴────┘│ │ │││││ 一重引用符付き(')DATE ───────────────────────────┴──────────┘ │││││ 引用符のない関数 ─────────────────────────────────────────┴┴┴┴ ┴┘
変数の引用パターンは変わりませんが、変数を文字列に直接補間する場合、PHPでは二重引用符で囲む必要があります。ただし、SQL で使用するために変数を適切にエスケープしていることを確認してください。(SQLインジェクション対策として、プリペアドステートメントをサポートするAPIを代わりに使用することをお勧めします)。
//同じように変数を置き換えてみましょう。 // ここでは、変数テーブル名$tableをバックティッククオートにし、VALUESリストの変数 // VALUESリストの中の変数はシングルクオートになっています。 $query = "INSERT INTO `$table` (`id`, `col1`, `col2`, `date`) VALUES (NULL, '$val1', '$val2', '$date')";
プリペアドステートメントを使用する際には、ステートメントのプレースホルダーを引用する必要があるかどうかをドキュメントで確認してください。 PHP で最もよく使われている API である PDO や MySQLi は、引用符で囲まれていないプレースホルダを想定しており、 他の言語で使われているほとんどのプリペアドステートメント API も同様です。
// PDO example with named parameters, unquoted
$query = "INSERT INTO `table` (`id`, `col1`, `col2`, `date`) VALUES (:id, :col1, :col2, :date)";
// MySQLi example with ? parameters, unquoted
$query = "INSERT INTO `table` (`id`, `col1`, `col2`, `date`) VALUES (?, ?, ?, ?)";
MySQLのドキュメントによると、以下の文字セットを使用した識別子をクォート(バックティック)する必要はありません。
ASCII:
[0-9,a-z,A-Z$_]
(基本的なラテン文字、数字0-9、ドル、アンダースコア)
この文字セット以外の文字をテーブルやカラムの識別子として使用することは可能ですが、その場合は_必ず引用符(バックティック)を付けなければなりません(例:ホワイトスペース)。
バックティックは一般的に「識別子」を示すために使用され、誤って予約キーワードを使用してしまわないように**安全性を確保するためにも使用されます。
例えば、以下のようになります。
Use `database`;
ここで、バックティックは、database
が実際にはデータベースの名前であり、データベースの識別子ではないことをサーバーが理解するのに役立ちます。
同じことがテーブル名やフィールド名にもできます。データベース識別子をバックティックで囲むと、とても良い習慣になります。
バックスティックについてもっと知りたい方は、こちらをご覧ください。
二重引用符と一重引用符について(Michaelがすでに述べています)。
しかし、値を定義するには、シングルクォートかダブルクォートを使わなければなりません。別の例を見てみましょう。
INSERT INTO `tablename` (`id, `title`) VALUES ( NULL, title1);
ここでは、title1
をわざと引用符で囲むのを忘れています。これでサーバーは、title1
をカラム名(つまり識別子)とみなします。そのため、値であることを示すには、ダブルクォートかシングルクォートを使用しなければなりません。
INSERT INTO `tablename` (`id, `title`) VALUES ( NULL, 'title1');
さて、PHPとの組み合わせで、ダブルクォートとシングルクォートを使えば、クエリを書く時間がずっと楽になります。ご質問のクエリを修正したものを見てみましょう。
$query = "INSERT INTO `table` (`id`, `col1`, `col2`) VALUES (NULL, '$val1', '$val2')";
ここで、PHPでダブルクォートを使用すると、変数 $val1
と $val2
に値を使用するようになり、完全に有効なクエリを作成することができます。このように
$val1 = "my value 1";
$val2 = "my value 2";
$query = "INSERT INTO `table` (`id`, `col1`, `col2`) VALUES (NULL, '$val1', '$val2')";
のようにすると
INSERT INTO `table` (`id`, `col1`, `col2`) VALUES (NULL, 'my value 1', 'my value 2')
テーブルのcolや値が変数の場合、2つの方法があります。
二重引用符 ""
を使って、完全なクエリを表示します。
$query = "INSERT INTO $table_name (id, $col1, $col2)
VALUES (NULL, '$val1', '$val2')";
または
$query = "INSERT INTO ".$table_name." (id, ".$col1.", ".$col2.")
VALUES (NULL, '".$val1."', '".$val2."')";
シングルクォート `''を使って
$query = 'INSERT INTO '.$table_name.' (id, '.$col1.', '.$col2.')
VALUES (NULL, '.$val1.', '.$val2.')';
カラム/値の名前がMySQLの予約済みキーワードに似ている場合、バックティック ``` `` を使用します。
注: カラム名をテーブル名で表している場合は、以下のようにバックティックを使用します。
テーブル名
.
table_name``. ``column_name
`<-- 注意: バックティックから
.` を除外してください。