ConFoo: Call for paper is now Open

oci_fetch_array

(PHP 5, PECL OCI8 >= 1.1.0)

oci_fetch_arrayクエリの次の行を連想配列あるいは数値添字配列で返す

説明

array oci_fetch_array ( resource $statement [, int $mode ] )

クエリから、結果セットの次の行を含む配列を返します。 配列の各エントリが行の各カラムをあらわします。 この関数の典型的な使い方は、ループの中で FALSE を返すまでコールすることです。 FALSE は、もう行がないことを意味します。

statement が Oracle Database 12c の暗黙の結果セットを返す PL/SQL ブロックである場合、 すべてのセットからの行を続けて取得します。 statementoci_get_implicit_resultset() の戻す値である場合、 ひとつの子クエリーからの行のサブセットだけを返します。

OCI8 拡張モジュールによるデータ型マッピングの 詳細については、ドライバが サポートするデータ型 を参照ください。

パラメータ

statement

oci_parse() で作成して oci_execute() で実行した有効な OCI8 ステートメント ID、 あるいは REF CURSOR ステートメント ID。

oci_get_implicit_resultset() が戻すステートメント ID も指定できます。

mode

オプションの第2引数は、次の定数の組み合わせが可能です。

oci_fetch_array() のモード
定数 説明
OCI_BOTH 連想配列と配列の両方を返します。 これは OCI_ASSOC + OCI_NUM と同等で、 デフォルトの動作です。
OCI_ASSOC 連想配列を返します。
OCI_NUM 数値添字配列を返します。
OCI_RETURN_NULLS NULL フィールドの要素も作成します。この要素の値は PHP の NULL となります。
OCI_RETURN_LOBS LOB ディスクリプタではなく LOB の中身を返します。

デフォルトの modeOCI_BOTH です。

加算演算子 "+" を使うと、複数のモードを同時に指定できます。

返り値

連想配列や数値添字配列を返します。 statement にもう行がない場合は FALSE を返します。

デフォルトでは、LOB カラムは LOB ディスクリプタを返します。

DATE カラムは、現行のデータフォーマットにフォーマットされた 文字列として返されます。既定のフォーマットは NLS_LANG のような Oracle 環境変数で変更したり、またはあらかじめ ALTER SESSION SET NLS_DATE_FORMAT コマンドを実行して変更します。

Oracle のデフォルトでは、大文字小文字を区別しないカラム名はすべて大文字となり、 結果の連想配列のインデックスも大文字になります。 大文字小文字を区別するカラム名は、配列のインデックスもそれと同じになります。 結果の配列を var_dump() すれば、 各クエリの大文字小文字を確かめることができます。

テーブル名は配列のインデックスには含まれません。 もし同じ名前の別カラムを複数取得するクエリを実行する場合は、 OCI_NUM を使うか、あるいはカラムのエイリアスを指定して名前の一意性を保ちましょう。 例 7 を参照ください。そうしなければ、PHP からはひとつのカラムだけしか見えなくなります。

例1 oci_fetch_array() での OCI_BOTH の使用例

<?php

$conn 
oci_connect('hr''welcome''localhost/XE');
if (!
$conn) {
    
$e oci_error();
    
trigger_error(htmlentities($e['message'], ENT_QUOTES), E_USER_ERROR);
}

$stid oci_parse($conn'SELECT department_id, department_name FROM departments');
oci_execute($stid);

while ((
$row oci_fetch_array($stidOCI_BOTH)) != false) {
    
// 連想配列の指標として大文字のカラム名を使用します
    
echo $row[0] . " and " $row['DEPARTMENT_ID']   . " are the same<br>\n";
    echo 
$row[1] . " and " $row['DEPARTMENT_NAME'] . " are the same<br>\n";
}

oci_free_statement($stid);
oci_close($conn);

?>

例2 oci_fetch_array() での OCI_NUM の使用例

<?php

/*
  実行する前にテーブルを作成します。
      CREATE TABLE mytab (id NUMBER, description CLOB);
      INSERT INTO mytab (id, description) values (1, 'A very long string');
      COMMIT;
*/

$conn oci_connect('hr''welcome''localhost/XE');
if (!
$conn) {
    
$e oci_error();
    
trigger_error(htmlentities($e['message'], ENT_QUOTES), E_USER_ERROR);
}

$stid oci_parse($conn'SELECT id, description FROM mytab');
oci_execute($stid);

while ((
$row oci_fetch_array($stidOCI_NUM)) != false) {
    echo 
$row[0] . "<br>\n";
    echo 
$row[1]->read(11) . "<br>\n"// DESCRIPTION から最初の 11 バイトを出力します
}

// 出力です。
//    1
//    A very long

oci_free_statement($stid);
oci_close($conn);

?>

例3 oci_fetch_array() での OCI_ASSOC の使用例

<?php

/*
  実行する前にテーブルを作成します。
      CREATE TABLE mytab (id NUMBER, description CLOB);
      INSERT INTO mytab (id, description) values (1, 'A very long string');
      COMMIT;
*/

$conn oci_connect('hr''welcome''localhost/XE');
if (!
$conn) {
    
$e oci_error();
    
trigger_error(htmlentities($e['message'], ENT_QUOTES), E_USER_ERROR);
}

$stid oci_parse($conn'SELECT id, description FROM mytab');
oci_execute($stid);

while ((
$row oci_fetch_array($stidOCI_ASSOC)) != false) {
    echo 
$row['ID'] . "<br>\n";
    echo 
$row['DESCRIPTION']->read(11) . "<br>\n"// DESCRIPTION から最初の 11 バイトを出力します
}

// 出力です。
//    1
//    A very long

oci_free_statement($stid);
oci_close($conn);

?>

例4 oci_fetch_array() での OCI_RETURN_NULLS の使用例

<?php

$conn 
oci_connect('hr''welcome''localhost/XE');
if (!
$conn) {
    
$e oci_error();
    
trigger_error(htmlentities($e['message'], ENT_QUOTES), E_USER_ERROR);
}

$stid oci_parse($conn'SELECT 1, null FROM dual');
oci_execute($stid);
while ((
$row oci_fetch_array ($stidOCI_ASSOC)) != false) { // NULL を無視
    
var_dump($row);
}

/*
上記のコードの出力です。
  array(1) {
    [1]=>
    string(1) "1"
  }
*/

$stid oci_parse($conn'SELECT 1, null FROM dual');
oci_execute($stid);
while ((
$row oci_fetch_array ($stidOCI_ASSOC+OCI_RETURN_NULLS)) != false) { // NULL をフェッチ
    
var_dump($row);
}

/*
上記のコードの出力です。
  array(2) {
    [1]=>
    string(1) "1"
    ["NULL"]=>
    NULL
  }
*/

?>

例5 oci_fetch_array() での OCI_RETURN_LOBS の使用例

<?php

/*
  実行する前にテーブルを作成します。
      CREATE TABLE mytab (id NUMBER, description CLOB);
      INSERT INTO mytab (id, description) values (1, 'A very long string');
      COMMIT;
*/

$conn oci_connect('hr''welcome''localhost/XE');
if (!
$conn) {
    
$e oci_error();
    
trigger_error(htmlentities($e['message'], ENT_QUOTES), E_USER_ERROR);
}

$stid oci_parse($conn'SELECT id, description FROM mytab');
oci_execute($stid);

while ((
$row oci_fetch_array($stidOCI_ASSOC+OCI_RETURN_LOBS)) != false) {
    echo 
$row['ID'] . "<br>\n";
    echo 
$row['DESCRIPTION'] . "<br>\n"// DESCRIPTION の全てが含まれます
    // ループ内で、大きなサイズの変数を解放してから次のフェッチに進めます。
    // これで、PHP のピークメモリ利用量を抑えます。
    
unset($row);
}

// 出力です。
//    1
//    A very long string

oci_free_statement($stid);
oci_close($conn);

?>

例6 oci_fetch_array() での文字の大小を区別するカラムの使用例

<?php

/*
   実行する前にテーブルを作成します。
      CREATE TABLE mytab ("Name" VARCHAR2(20), city VARCHAR2(20));
      INSERT INTO mytab ("Name", city) values ('Chris', 'Melbourne');
      COMMIT;
*/

$conn oci_connect('hr''welcome''localhost/XE');
if (!
$conn) {
    
$e oci_error();
    
trigger_error(htmlentities($e['message'], ENT_QUOTES), E_USER_ERROR);
}

$stid oci_parse($conn'select * from mytab');
oci_execute($stid);
$row oci_fetch_array($stidOCI_ASSOC+OCI_RETURN_NULLS);

// 'Name' は文字の大小を区別するカラムとして作成されたので、配列の指標として
// 同一のケースを使用します。しかしながら、文字の大小を区別しないカラムの
// 指標としては、大文字の 'CITY' を使わなければいけません。
print $row['Name'] . "<br>\n";   //  Chris を出力
print $row['CITY'] . "<br>\n";   //  Melbourne を出力

oci_free_statement($stid);
oci_close($conn);

?>

例7 oci_fetch_array() での同じ名前のカラムの使用例

<?php

/*
  実行する前にテーブルを作成します。
      CREATE TABLE mycity (id NUMBER, name VARCHAR2(20));
      INSERT INTO mycity (id, name) values (1, 'Melbourne');
      CREATE TABLE mycountry (id NUMBER, name VARCHAR2(20));
      INSERT INTO mycountry (id, name) values (1, 'Australia');
      COMMIT;
*/

$conn oci_connect('hr''welcome''localhost/XE');
if (!
$conn) {
    
$e oci_error();
    
trigger_error(htmlentities($e['message'], ENT_QUOTES), E_USER_ERROR);
}

$sql 'SELECT mycity.name, mycountry.name
        FROM mycity, mycountry
        WHERE mycity.id = mycountry.id'
;
$stid oci_parse($conn$sql);
oci_execute($stid);
$row oci_fetch_array($stidOCI_ASSOC);
var_dump($row);

// 出力には "NAME" 項目一つだけが含まれます。
//    array(1) {
//      ["NAME"]=>
//      string(9) "Australia"
//    }

// 度重なるカラム名を照会するには、 "AS ctnm" のような SQL カラムのエイリアスを使います。
$sql 'SELECT mycity.name AS ctnm, mycountry.name 
        FROM mycity, mycountry 
        WHERE mycity.id = mycountry.id'
;
$stid oci_parse($conn$sql);
oci_execute($stid);
$row oci_fetch_array($stidOCI_ASSOC);
var_dump($row);

// これで出力には選択したカラムが両方含まれます。
//    array(2) {
//      ["CTNM"]=>
//      string(9) "Melbourne"
//      ["NAME"]=>
//      string(9) "Australia"
//    }


oci_free_statement($stid);
oci_close($conn);

?>

例8 oci_fetch_array() での DATE カラムの使用例

<?php

$conn 
oci_connect('hr''welcome''localhost/XE');
if (!
$conn) {
    
$e oci_error();
    
trigger_error(htmlentities($e['message'], ENT_QUOTES), E_USER_ERROR);
}

// この接続に対して日付フォーマットを設定します。
// パフォーマンス上の理由で、トリガー、またはその代わりに環境変数で
// フォーマットを変更することを検討します
$stid oci_parse($conn"ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD'");
oci_execute($stid);

$stid oci_parse($conn'SELECT hire_date FROM employees WHERE employee_id = 188');
oci_execute($stid);
$row oci_fetch_array($stidOCI_ASSOC);
echo 
$row['HIRE_DATE'] . "<br>\n";  // 1997-06-14 を出力

oci_free_statement($stid);
oci_close($conn);

?>

例9 oci_fetch_array() での REF CURSOR の使用例

<?php
/*
  下記のようにして PL/SQL ストアド・プロシジャーを作成します。

  CREATE OR REPLACE PROCEDURE myproc(p1 OUT SYS_REFCURSOR) AS
  BEGIN
    OPEN p1 FOR SELECT * FROM all_objects WHERE ROWNUM < 5000;
  END;
*/

$conn oci_connect('hr''welcome''localhost/XE');
if (!
$conn) {
    
$e oci_error();
    
trigger_error(htmlentities($e['message'], ENT_QUOTES), E_USER_ERROR);
}

$stid oci_parse($conn'BEGIN myproc(:rc); END;');
$refcur oci_new_cursor($conn);
oci_bind_by_name($stid':rc'$refcur, -1OCI_B_CURSOR);
oci_execute($stid);

// 返された REF CURSOR を実行して、ステートメント識別子のようにそこからフェッチします
oci_execute($refcur);  
echo 
"<table border='1'>\n";
while ((
$row oci_fetch_array($refcurOCI_ASSOC+OCI_RETURN_NULLS)) != false) {
    echo 
"<tr>\n";
    foreach (
$row as $item) {
        echo 
"    <td>".($item !== null htmlentities($itemENT_QUOTES) : "&nbsp;")."</td>\n";
    }
    echo 
"</tr>\n";
}
echo 
"</table>\n";

oci_free_statement($refcur);
oci_free_statement($stid);
oci_close($conn);

?>

例10 oci_fetch_array() での LIMIT 風のクエリによるページング

<?php

$conn 
oci_connect('hr''welcome''localhost/XE');
if (!
$conn) {
    
$e oci_error();
    
trigger_error(htmlentities($e['message'], ENT_QUOTES), E_USER_ERROR);
}

// データベースのバージョンを調べます
preg_match('/Release ([0-9]+)\./'oci_server_version($conn), $matches);
$oracleversion $matches[1];

// これがページングさせたいクエリーです
$sql 'SELECT city, postal_code FROM locations ORDER BY city';

if (
$oracleversion >= 12) {
    
// Oracle 12c の OFFSET / FETCH NEXT 構文を使います
    
$sql $sql ' OFFSET :offset ROWS FETCH NEXT :numrows ROWS ONLY';
} else {
    
// 古いバージョンの Oracle では、ネストしたクエリーを作り、$sql から
    // 行のサブセットを選択する必要があります。あるいは、開発時に SQL 文が
    // わかっているのなら、この方法ではなく row_number() 関数を使うことを
    // 検討しましょう。運用環境では、文字列の連結にともなう SQL インジェクション
    // の問題に気をつけましょう。
    
$sql "SELECT * FROM (SELECT a.*, ROWNUM AS my_rnum
                           FROM (
$sql) a
                           WHERE ROWNUM <= :offset + :numrows)
            WHERE my_rnum > :offset"
;
}

$offset  0;  // この行数だけ飛ばす
$numrows 5;  // 5 行を返す
$stid oci_parse($conn$sql);
oci_bind_by_name($stid':numrows'$numrows);
oci_bind_by_name($stid':offset'$offset);
oci_execute($stid);

while ((
$row oci_fetch_array($stidOCI_ASSOC OCI_RETURN_NULLS)) != false) {
    echo 
$row['CITY'] . " " $row['POSTAL_CODE'] . "<br>\n";
}

// 出力は
//    Beijing 190518
//    Bern 3095
//    Bombay 490231
//    Geneva 1730
//    Hiroshima 6823

oci_free_statement($stid);
oci_close($conn);

?>

例11 oci_fetch_array() で Oracle Database 12c の暗黙の結果セットを使う例

<?php

$conn 
oci_connect('hr''welcome''localhost/pdborcl');
if (!
$conn) {
    
$e oci_error();
    
trigger_error(htmlentities($e['message'], ENT_QUOTES), E_USER_ERROR);
}

// OCI8 2.0 と Oracle Database 12c が必要です。
// oci_get_implicit_resultset() も参照ください。
$sql 'DECLARE
           c1 SYS_REFCURSOR;
        BEGIN
           OPEN c1 FOR SELECT city, postal_code FROM locations WHERE ROWNUM < 4 ORDER BY city;
           DBMS_SQL.RETURN_RESULT(c1);
           OPEN c1 FOR SELECT country_id FROM locations WHERE ROWNUM < 4 ORDER BY city;
           DBMS_SQL.RETURN_RESULT(c1);
        END;'
;

$stid oci_parse($conn$sql);
oci_execute($stid);

// 注意: oci_fetch_all と oci_fetch() は、この場合は使えません
echo "<table>\n";
while ((
$row oci_fetch_array($stidOCI_ASSOC+OCI_RETURN_NULLS)) != false) {
    echo 
"<tr>\n";
    foreach (
$row as $item) {
        echo 
"  <td>".($item!==null?htmlentities($itemENT_QUOTES|ENT_SUBSTITUTE):"&nbsp;")."</td>\n";
    }
    echo 
"</tr>\n";
}
echo 
"</table>\n";

// 出力です。
//    Beijing 190518
//    Bern    3095
//    Bombay  490231
//    CN
//    CH
//    IN

oci_free_statement($stid);
oci_close($conn);

?>

注意

注意:

大文字小文字を区別せずにつくった Oracle のカラムでは、 連想配列のインデックスはすべて大文字となることに注意しましょう。

注意:

大量の行を返すクエリの場合、 oci8.default_prefetch を増やすか oci_set_prefetch() を使えばパフォーマンスが劇的に向上します。

注意:

oci_fetch_array()ほんの少しだけ oci_fetch_assoc()oci_fetch_row() より低速ですが、 ずっと柔軟性があります。

参考

add a note add a note

User Contributed Notes 2 notes

up
0
Maxwell_Smart at ThePentagon dot com
12 years ago
When using OCI_RETURN_LOBS to get a BFILE (stored with a DIRECTORY) the user needs READ on the DIRECTORY.  (GRANT READ on DIRECTORY <directory name> TO <user>;) Otherwise, you'll get a cryptic error. Warning: OCILobFileOpen: ORA-22285: non-existent directory or file for FILEOPEN operation in ... on line ...
<BR>
The user that CREATEs the DIRECTORY is automatically GRANTed READ WITH THE GRANT OPTION.
up
0
junk at netburp dot com
13 years ago
Here's a clue about rowid.

Don't forget about the oracle functions:

"rowidtochar" and "chartorowid"

"select rowidtochar(rowid) as FOO from table ...."

When you want to pass the rowid in a form or link, that's
the only way to go.
To Top