挿入クエリ
挿入クエリは常にクエリビルダーオブジェクトを使用する必要があります。一部のデータベースでは、LOB(Large OBject、例:MySQLのTEXT)およびBLOB(Binary Large OBject)フィールドの特別な処理が必要です。したがって、個々のデータベースドライバーが必要な特別な処理を実装できるように、抽象化レイヤーが必要です。
挿入クエリはinsert()メソッドを使用して次のように開始します:
$query = $connection->insert('mytable', $options);
これにより、mytableテーブルに1つ以上のレコードを挿入する挿入クエリオブジェクトが作成されます。テーブル名に中括弧は不要です。クエリビルダーが自動的に処理するためです。
挿入クエリオブジェクトは流れるようなAPIを使用します。つまり、execute()を除くすべてのメソッドがクエリオブジェクト自体を返すため、メソッド呼び出しを連結できます。多くの場合、これはクエリオブジェクトを変数に保存する必要がまったくないことを意味します。
挿入クエリオブジェクトは、さまざまなニーズを満たすために複数の異なる使用パターンをサポートしています。一般的に、ワークフローは、クエリが挿入するフィールドの指定、それらのフィールドにクエリが挿入する値の定義、クエリの実行で構成されます。最も一般的な推奨使用パターンを以下に示します。
コンパクト形式
ほとんどの挿入クエリで推奨される形式はコンパクト形式です:
$result = $connection->insert('mytable')
->fields([
'title' => 'Example',
'uid' => 1,
'created' => \Drupal::time()->getRequestTime(),
])
->execute();
これは次のクエリと同等になります:
INSERT INTO {mytable} (title, uid, created) VALUES ('Example', 1, 1221717405);
上記のフラグメントは、挿入プロセスの主要部分を組み合わせています。
$connection->insert('mytable')
この行は、mytableテーブル用の新しい挿入クエリオブジェクトを作成します。
->fields([
'title' => 'Example',
'uid' => 1,
'created' => \Drupal::time()->getRequestTime(),
])
fields()メソッドはいくつかのパラメーター形式を受け入れますが、最も一般的に使用されるのは単一の連想配列です。配列のキーは挿入するテーブルの列で、値は挿入する対応する値です。これにより、指定されたテーブルへの単一の挿入クエリになります。
->execute();
execute()メソッドはクエリに実行を指示します。このメソッドが呼び出されない場合、クエリは実行されません。
クエリオブジェクト自体を返す挿入クエリオブジェクトの他のメソッドとは異なり、execute()は、挿入クエリによって入力された自動インクリメントフィールド(hook_schema()のシリアル型)の値を返します(存在する場合)。そのため、上記の例では、その戻り値が$resultに割り当てられています。自動インクリメントフィールドがない場合、execute()の戻り値は未定義であり、信頼できません。
典型的な場合、これは挿入クエリに推奨される形式です。
Degenerate form
$result = $connection->insert('mytable')
->fields(['title', 'uid', 'created'])
->values([
'title' => 'Example',
'uid' => 1,
'created' => \Drupal::time()->getRequestTime(),
])
->execute();
これは前のクエリのやや冗長な同等物で、まったく同じ結果になります。
->fields(['title', 'uid', 'created'])
fields()が連想配列ではなくインデックス付き配列で呼び出されると、クエリで使用されるフィールド(データベース列)のみが設定され、それらの値は設定されません。これは、後で複数ページのクエリを実行する場合に便利です。
->values([
'title' => 'Example',
'uid' => 1,
'created' => \Drupal::time()->getRequestTime(),
])
このメソッド呼び出しは、フィールド名と、それらのフィールドに挿入する値の連想配列を設定します。values()メソッドはインデックス付き配列も受け取ることができます。インデックス付き配列を使用する場合、値の順序はfields()メソッドのフィールドの順序と一致している必要があります。連想配列を使用する場合、任意の順序で構いません。通常、読みやすさの観点から連想配列が好まれます。
この形式のクエリは、コンパクト形式が推奨されるため、あまり使用されません。ほとんどの場合、fields()とvalues()を分離する唯一の理由は、複数ページのクエリを実行することです。
複数挿入形式
挿入クエリオブジェクトは複数の値セットも受け取ることができます。つまり、values()を複数回呼び出して、複数の挿入ステートメントをキューに入れることができます。これが正確にどのように行われるかは、対象のデータベースの機能によって異なります。ほとんどのデータベースでは、データの整合性と速度を高めるため、複数の挿入ステートメントがトランザクション内でまとめて実行されます。MySQLでは、MySQLの複数値挿入構文が使用されます。
$values = [
[
'title' => 'Example',
'uid' => 1,
'created' => \Drupal::time()->getRequestTime(),
],
[
'title' => 'Example 2',
'uid' => 1,
'created' => \Drupal::time()->getRequestTime(),
],
[
'title' => 'Example 3',
'uid' => 2,
'created' => \Drupal::time()->getRequestTime(),
],
];
$query = $connection->insert('mytable')->fields(['title', 'uid', 'created']);
foreach ($values as $record) {
$query->values($record);
}
$query->execute();
上記の例では、使用される特定のデータベースドライバーに最も効率的な方法を使用して、3つの挿入ステートメントがまとめて実行されます。ここでは、$valuesをループしてvalues()メソッドを再度呼び出せるように、クエリオブジェクトを変数に保存していることに注意してください。
縮退した場合、上記の例は次の3つのクエリと同等です:
INSERT INTO {mytable} (title, uid, created) VALUES ('Example', 1, 1221717405);
INSERT INTO {mytable} (title, uid, created) VALUES ('Example2', 1, 1221717405);
INSERT INTO {mytable} (title, uid, created) VALUES ('Example3', 2, 1221717405);
複数挿入クエリでは、execute()の戻り値は未定義であり、データベースドライバーによって異なる可能性があるため、信頼すべきではありません。
selectクエリの結果からの挿入
テーブルを他のテーブルの結果で埋めたい場合、元のテーブルからSELECTしてPHPでデータをループ処理し、新しいテーブルに挿入するか、SELECTクエリから返される各レコードがINSERTクエリに供給されるINSERT INTO ... SELECT FROMクエリを実行する必要があります。
この例では、typeがpageのシステム内のすべてのノードについて、nidとユーザー名を持つmytableテーブルを構築します。
<?php
// Build the SELECT query.
$query = $connection->select('node', 'n');
// Join to the users table.
$query->join('users', 'u', 'n.uid = u.uid');
// Add the fields we want.
$query->addField('n','nid');
$query->addField('u','name');
// Add a condition to only get page nodes.
$query->condition('type', 'page');
// Perform the insert.
$connection->insert('mytable')
->from($query)
->execute();
?>
デフォルト値
通常、特定のフィールドの値を指定せず、テーブルスキーマでデフォルト値が定義されている場合、データベースは自動的にそのデフォルト値を挿入します。ただし、データベースにデフォルト値の使用を明示的に指示する必要がある場合もあります。これには、レコード全体にすべてのデフォルト値を使用したい場合が含まれます。特定のフィールドにデフォルト値を使用するようデータベースに明示的に指示するには、useDefaults()メソッドがあります。
$query->useDefaults(['field1', 'field2']);
この行は、field1およびfield2フィールドのデフォルト値を使用するようクエリに指示します。useDefaults()とfields()またはvalues()の両方で同じフィールドを指定することはエラーであり、例外がスローされることに注意してください。
$connection->insert() or $connection->query()
これはよくある質問です。(このページのコメントを参照してください。)insert()とquery()の違いは何ですか?
insert()メソッドでは、各列がフィールド配列の個別のエントリとして指定され、コードは各列の値をサニタイズできます。query()には、個々の列を検査する機能のないSQL文字列があります。プレースホルダー付きでquery()を使用すると、コードは列の値を検査できますが、プレースホルダーは単なるオプションであり、SQLにプレースホルダーを通さない値が含まれていないことを保証する方法はありません。
insert()は、他のモジュールがクエリを検査・変更できるように、クエリをフックのセットに通します。これは他のモジュールと連携する正しい方法です。query()はクエリをフックに通さないため、少し高速です。処理時間を節約できますが、他のモジュールがコードを支援できなくなります。
insert()は、他のデータベースや将来のDrupalバージョンとより互換性があります。