PHP Conference Japan 2024

oci_fetch_array

(PHP 5, PHP 7, PHP 8, PECL OCI8 >= 1.1.0)

oci_fetch_array将查询中的下一行作为关联或数字数组返回

描述

oci_fetch_array(资源 $statement, 整数 $mode = OCI_BOTH | OCI_RETURN_NULLS): 数组|false

返回一个数组,其中包含查询的下一结果集行。每个数组条目对应于行的每一列。此函数通常在循环中调用,直到它返回false,表示不再存在行。

如果statement对应于返回 Oracle 数据库隐式结果集的 PL/SQL 块,则连续获取所有集中的行。如果statementoci_get_implicit_resultset()返回,则仅返回一个子查询的行子集。

有关 OCI8 扩展执行的数据类型映射的详细信息,请参阅驱动程序支持的数据类型

参数

statement

oci_parse()创建并由oci_execute()执行的有效 OCI8 语句标识符,或REF CURSOR语句标识符。

也可以是由oci_get_implicit_resultset()返回的语句标识符。

mode

可选的第二个参数可以是以下常量的任意组合

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列作为格式化为当前日期格式的字符串返回。默认格式可以使用 Oracle 环境变量(如NLS_LANG)或先前执行的ALTER SESSION SET NLS_DATE_FORMAT命令更改。

Oracle 的默认不区分大小写的列名在结果数组中具有大写关联索引。区分大小写的列名将具有使用精确列大小写的数组索引。对结果数组使用var_dump()以验证每个查询应使用的适当大小写。

表名未包含在数组索引中。如果您的查询包含两个具有相同名称的不同列,请使用OCI_NUM或向查询添加列别名以确保名称唯一性,请参阅示例 #7。否则,将仅通过 PHP 返回一列。

示例

示例 #1 使用OCI_BOTHoci_fetch_array()

<?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($stid, OCI_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_NUMoci_fetch_array()

<?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($stid, OCI_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_ASSOCoci_fetch_array()

<?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($stid, OCI_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_RETURN_NULLSoci_fetch_array()

<?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 ($stid, OCI_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 ($stid, OCI_ASSOC+OCI_RETURN_NULLS)) != false) { // 获取NULL值
var_dump($row);
}

/*
以上代码输出:
array(2) {
[1]=>
string(1) "1"
["NULL"]=>
NULL
}
*/

?>

示例 #5 使用OCI_RETURN_LOBSoci_fetch_array()

<?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($stid, OCI_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($stid, OCI_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($stid, OCI_ASSOC);
var_dump($row);

// 输出只包含一个 "NAME" 条目:
// array(1) {
// ["NAME"]=>
// string(9) "Australia"
// }

// 要查询重复的列名,请使用 SQL 列别名,例如 "AS ctnm":
$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($stid, OCI_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($stid, OCI_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, -1, OCI_B_CURSOR);
oci_execute($stid);

// 执行返回的 REF CURSOR,并像语句标识符一样从中获取数据
oci_execute($refcur);
echo
"<table border='1'>\n";
while ((
$row = oci_fetch_array($refcur, OCI_ASSOC+OCI_RETURN_NULLS)) != false) {
echo
"<tr>\n";
foreach (
$row as $item) {
echo
" <td>".($item !== null ? htmlentities($item, ENT_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($stid, OCI_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 Oracle 数据库隐式结果集与 oci_fetch_array()

<?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 数据库 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($stid, OCI_ASSOC+OCI_RETURN_NULLS)) != false) {
echo
"<tr>\n";
foreach (
$row as $item) {
echo
" <td>".($item!==null?htmlentities($item, ENT_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() 稍微慢一些,但更灵活。

参见

添加注释

用户贡献的注释 2 条注释

Maxwell_Smart at ThePentagon dot com
22 年前
当使用 OCI_RETURN_LOBS 获取 BFILE(与 DIRECTORY 存储在一起)时,用户需要对 DIRECTORY 进行读取权限。(GRANT READ on DIRECTORY <directory name> TO <user>;)否则,您将收到一个难以理解的错误。警告:OCILobFileOpen:ORA-22285:FILEOPEN 操作的目录或文件不存在,位于 ... 第 ... 行
<BR>
创建 DIRECTORY 的用户会自动授予具有 GRANT OPTION 的 READ 权限。
junk at netburp dot com
24 年前
这是一个关于 rowid 的提示。

不要忘记 Oracle 函数

"rowidtochar" 和 "chartorowid"

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

当您想在表单或链接中传递 rowid 时,这是
唯一的方法。
To Top