ヘッダーをスキップ
Oracle® Database Express Edition 2日でPHP開発者ガイド
11g リリース 2 (11.2)
B66464-01
  目次へ移動
目次
索引へ移動
索引

前
 
次
 

10 複数データ値の挿入

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.phpgetcleanequip()関数を置き換えます。

/**
 * 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.phpdoinsert()を次に置き換えます。

/**
 * 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」リンクをクリックします。

「Add Multiple」リンクを含む従業員リスト

ComputerMonitorKeyboardなどのデータ項目を追加します。

複数挿入フォーム

「Submit」をクリックし、Steven Kingの横の「Show」をクリックしてデータ項目が挿入されたことを確認します。

複数入力

配列バインディングはデータのフェッチにも機能します。効率的なBULK COLLECT構文を使用したPL/SQLプロシージャでは、1回のOCI8 oci_execute()コールでデータをPHPに返すことができます。Oracleからデータを取得する際、PHPがメモリーを正しく割り当てるためには、oci_bind_array_by_name()コールが項目数と最大データ・サイズを認識している必要があります。