PHP OCI8では、文字や整数の配列を1回のコールで挿入できます。そのため、複数の値を表に挿入する際の、ネットワーク・トラフィックおよびデータベース・システムのオーバーヘッドを削減できます。
この章のトピックは、次のとおりです。
この章の例では、3つのデータ値を1回の操作で挿入できるフォームについて説明します。
配列の挿入には、PL/SQLのバルクFORALL
コマンドを使用します。SQL*PlusにHR
としてログインし、PL/SQLパッケージを作成します。
CREATE OR REPLACE PACKAGE equip_pkg AS TYPE arrtype IS TABLE OF VARCHAR2(20) INDEX BY PLS_INTEGER; PROCEDURE insert_equip(eid_p IN NUMBER, eqa_p IN arrtype); END equip_pkg; /
CREATE OR REPLACE PACKAGE BODY equip_pkg AS PROCEDURE insert_equip(eid_p IN NUMBER, eqa_p IN arrtype) IS BEGIN FORALL i IN INDICES OF eqa_p INSERT INTO equipment (employee_id, equip_name) VALUES (eid_p, eqa_p(i)); END insert_equip; END equip_pkg; /
insert_equip()
プロシージャは従業員名の配列を受け入れて、EQUIPMENT
表に挿入します。
新規のPHPファイルac_add_multi.php
を作成し、ここにac_add_one.php
のコンテンツをコピーします。値の配列を処理できるようにするため、ファイルに次の変更を加えます。
ac_add_multi.php
のHTMLフォームで、次の1件入力フィールドを変更します。
<div> Equipment name <input type="text" name="equip"><br> <input type="hidden" name="empid" value="$empid"> ...
3件入力フィールドへの変更
... <div> Equipment name <input type="text" name="equip[]"><br> Equipment name <input type="text" name="equip[]"><br> Equipment name <input type="text" name="equip[]"><br> <input type="hidden" name="empid" value="$empid"> ...
[]
トークンは配列を返します。これはac_add_one.php
では必要ありませんでした。
返されたフォームの値を処理できるようにするため、ac_add_multi.php
のgetcleanequip()
関数を置き換えます。
/** * Perform validation and data cleaning so empty strings are not inserted * * @return array The array of new data to enter */ function getcleanequip() { if (!isset($_POST['equip'])) { return array(); } else { $equiparr = array(); foreach ($_POST['equip'] as $v) { // Strip out unset values $v = trim($v); if (!empty($v)) $equiparr[] = $v; } return($equiparr); } }
配列の各エントリをループ処理し、空でない文字列のみを返します。
最後に、ac_add_multi.php
のdoinsert()
を次に置き換えます。
/** * Insert an array of equipment values for an employee * * @param Db $db * @param array $equiparr array of string values to be inserted * @param string $empid Employee identifier */ function doinsert($db, $equiparr, $empid) { $arraybinds = array(array("eqa", $equiparr, SQLT_CHR)); $otherbinds = array(array("eid", $empid, -1)); $sql = "BEGIN equip_pkg.insert_equip(:eid, :eqa); END;"; $db->arrayInsert($sql, "Insert Equipment List", $arraybinds, $otherbinds); }
これは、Db
クラスで新規のarrayInsert()
メソッドを使用して、PL/SQL insert_equip()
プロシージャをコールしています。データ値配列のバインドは通常のスカラーPHP OCI8バインドとは異なる方法で行う必要があるため、arrayInsert()
へのバインド・パラメータは2種類に分かれています。
ac_db.inc.phpを編集して、新規のメソッドを追加します。
/** * Insert an array of values by calling a PL/SQL procedure * * Call like Db::arrayinsert("begin myproc(:arn, :p); end", * "Insert stuff", * array(array(":arn", $dataarray, SQLT_CHR)), * array(array(":p", $p, -1))) * * @param string $sql PL/SQL anonymous block * @param string $action Action text for End-to-End Application Tracing * @param array $arraybindvars Bind variables. An array of tuples * @param array $otherbindvars Bind variables. An array of tuples */ public function arrayInsert($sql, $action, $arraybindvars, $otherbindvars = array()) { $this->stid = oci_parse($this->conn, $sql); foreach ($arraybindvars as $a) { // oci_bind_array_by_name(resource, bv_name, // php_array, php_array_length, max_item_length, datatype) oci_bind_array_by_name($this->stid, $a[0], $a[1], count($a[1]), -1, $a[2]); } foreach ($otherbindvars as $bv) { // oci_bind_by_name(resource, bv_name, php_variable, length) oci_bind_by_name($this->stid, $bv[0], $bv[1], $bv[2]); } oci_set_action($this->conn, $action); oci_execute($this->stid); // will auto commit $this->stid = null; }
Db::arrayInsert()
でのバインドは、このマニュアルの前述の例とほぼ同じです。データ配列の要素数を渡す必要があるため、oci_bind_array_by_name()
関数が受け取る引数はこれとは少し異なります。AnyCoアプリケーションのoci_bind_array_by_name
では、PHPからのデータを挿入するだけなので、最大データ長パラメータは-1
として渡すことができます。これは実際のデータ長を使用するようにPHPに指示しています。1回のoci_execute()
コールですべてのデータ項目がデータベースに挿入されます。
ファイルを保存し、ブラウザでAnyCoアプリケーションを実行します。Administrator
としてログインし、Steven Kingの「Add Multiple」リンクをクリックします。
Computer
、Monitor
、Keyboard
などのデータ項目を追加します。
「Submit」をクリックし、Steven Kingの横の「Show」をクリックしてデータ項目が挿入されたことを確認します。
配列バインディングはデータのフェッチにも機能します。効率的なBULK COLLECT
構文を使用したPL/SQLプロシージャでは、1回のOCI8 oci_execute()
コールでデータをPHPに返すことができます。Oracleからデータを取得する際、PHPがメモリーを正しく割り当てるためには、oci_bind_array_by_name()
コールが項目数と最大データ・サイズを認識している必要があります。