静的クエリ
Drupalで最も一般的なSELECTクエリは、データベース接続オブジェクトのquery()メソッドを使用した静的クエリです。
静的クエリはほぼそのままの形でデータベースに渡されます。
例:
$database = \Drupal::database();
$query = $database->query("SELECT id, example FROM {mytable}");
$result = $query->fetchAll();
非常に単純なSELECTクエリのみがstatic query()メソッドを使用する必要があります。より複雑なクエリ、動的クエリ生成、または可変性が必要な場合は、動的クエリを使用する必要があります。
単純なINSERT、UPDATE、DELETEクエリにはこの関数を使用しないでください。これらは、それぞれinsert()、update()、delete()を介して処理する必要があります。複数テーブルのより複雑なDELETEクエリについては、複雑なDELETEクエリを参照してください。
引数
データベース接続オブジェクトのquery()メソッドは3つの引数を受け取ります:
- $query:実行するクエリ。必要に応じてプレースホルダーを使用し、すべてのテーブル名を中括弧で囲んで示します。
- $args:クエリ内で置き換えるプレースホルダー値の配列。
- $options:クエリの動作を制御するオプションの配列(オプション)。
テーブル名のプレフィックス
静的クエリでは、すべてのテーブル名を中括弧{...}で囲む必要があります。
テーブル名を中括弧で囲むと、必要に応じてデータベースシステムがプレフィックス文字列を付けられるようにマークされます。プレフィックスを付けることで、複数のサイトを1つのデータベースから実行したり、場合によっては選択したテーブルをサイト間で共有したりできます。また、ホストサイトからテストへのデータ漏洩を防ぐためにも必要です。
プレースホルダー
プレースホルダーは、実行時にリテラルがクエリに挿入される場所を示します。プレースホルダーをクエリ自体から分離することで、データベースがSQL構文とユーザー指定の値を区別できるようになり、SQLインジェクション攻撃を防ぐことができます。
$query = $database->query("SELECT id, example FROM {mytable} WHERE created > :created", [
':created' => REQUEST_TIME - 3600,
]);
上記のコードは、過去1時間(3600秒)以内に作成されたすべてのmytable IDとexampleを選択します。:createdプレースホルダーは、クエリの実行時にREQUEST_TIME - 3600の値に動的に置き換えられます。
クエリには任意の数のプレースホルダーを含めることができますが、同じ値であってもすべて一意の名前を持つ必要があります。ユースケースに応じて、プレースホルダー配列は上記のようにインラインで指定することも、事前に構築して渡すこともできます。配列の順序は重要ではありません。
「db_」で始まるプレースホルダーはシステムの内部使用のために予約されており、明示的に指定してはいけません。
プレースホルダーは、そのタイプに関係なく、エスケープしたり引用符で囲んだりしてはいけないことに注意してください。プレースホルダーはデータベースサーバーに別々に渡されるため、サーバーはクエリ文字列と値を自分で区別できます。
// WRONG (quotes around the :type placeholder)
$result = $database->query("SELECT example FROM {mytable} WHERE type = ':type'", [
':type' => 'mytype',
]);
// CORRECT (no quotes around the :type placeholder)
$result = $database->query("SELECT example FROM {mytable} WHERE type = :type", [
':type' => 'mytype',
]);
プレースホルダーは列名とテーブル名には使用できません。代わりに、それらが安全でない入力から取得された場合は、$database->escapeTable()を介して実行する必要があります。
配列プレースホルダー
Drupalのデータベース層には、追加のプレースホルダー機能が含まれています。プレースホルダーに渡される値が配列の場合、対応するプレースホルダーとともに、カンマ区切りのリストに自動的に展開されます。つまり、開発者は必要なプレースホルダーの数を数えることを心配する必要がありません。
例でこの動作を明確にしましょう:
$result = $database->query("SELECT * FROM {mytable} WHERE id IN (:ids[])", [':ids[]' => [13, 42, 144]]);
次の2つのステートメントは、どちらも上記のステートメントと同等です:
$result = $database->query("SELECT * FROM {mytable} WHERE id IN (:ids_1, :ids_2, :ids_3)", [
':ids_1' => 13,
':ids_2' => 42,
':ids_3' => 144,
]);
$result = $database->query("SELECT * FROM {mytable} WHERE id IN (13, 42, 144)");
クエリオプション
データベース接続オブジェクトのquery()メソッドの3番目のパラメーターは、クエリの動作を定義するオプションの配列です。通常、ほとんどのクエリで使用されるディレクティブは2つだけです。他の値は主に内部使用向けです。
「target」キーは使用するターゲットを指定します。指定しない場合、デフォルトは「default」です。現在、他の有効な値は「replica」のみで、レプリカサーバーが存在する場合にそのサーバーに対してクエリを実行することを示します。
「fetch」キーは、このクエリから返されたレコードを取得する方法を指定します。有効な値は、PDO::FETCH_OBJ、PDO::FETCH_ASSOC、PDO::FETCH_NUM、PDO::FETCH_BOTH、またはクラス名を表す文字列です。文字列が指定された場合、各レコードはそのクラスの新しいオブジェクトにフェッチされます。他のすべての値の動作はPDOによって定義され、レコードをそれぞれstdClassオブジェクト、連想配列、数値配列、または数値キーと連想キーの両方を持つ配列としてフェッチします。http://php.net/manual/en/pdostatement.fetch.phpを参照してください。デフォルトはPDO::FETCH_OBJで、特に理由がない限り、一貫性のためにこれを使用する必要があります。
次の例では、レプリカサーバーが利用可能な場合にレプリカサーバーにクエリを実行し、結果セットからレコードを連想配列として取得します。
$result = $database->query("SELECT id, example FROM {mytable}", [], [
'target' => 'replica',
'fetch' => PDO::FETCH_ASSOC,
]);
query()メソッドの呼び出しによって返される結果オブジェクトを使用して、返された各行を取得できます。次の例では、$result変数にクエリのすべての返された行が含まれ、その後、個々の行がfetchAssoc()を使用して$row変数に1つずつ取得されます:
$sql = "SELECT name, quantity FROM goods WHERE vid = :vid";
$result = $database->query($sql, [':vid' => $vid]);
if ($result) {
while ($row = $result->fetchAssoc()) {
// Do something with:
// $row['name']
// $row['quantity']
}
}
複雑なDELETEクエリ
静的クエリを使用することは、1つのステートメントで複数のテーブルからの削除を含む削除クエリを表現する、シンプルでコンパクトな方法です。
例:
$database = \Drupal::database();
$database->query("DELETE {table1}, {table2} FROM {table1} INNER JOIN {table2} ON {table1}.id = {table2}.id WHERE {table1}.id=:recno", [":recno" => 2]);
(table1とtable2の両方から行を削除します)