2024 年日本 PHP 研討會

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 區塊,則會連續擷取所有集合中的列。如果 statement 是由 oci_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_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($stid, OCI_BOTH)) != false) {
// 使用大寫欄位名稱作為關聯陣列的索引
echo $row[0] . " 和 " . $row['DEPARTMENT_ID'] . " 相同<br>\n";
echo
$row[1] . " 和 " . $row['DEPARTMENT_NAME'] . " 相同<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, '一段很長的字串');
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
// 一段很長的字串

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 使用帶有 DATE 欄位的 oci_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, "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 使用 REF CURSORoci_fetch_array() 函式

<?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 使用類似 `LIMIT` 的查詢以 oci_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);
}

// Find the version of the database
preg_match('/Release ([0-9]+)\./', oci_server_version($conn), $matches);
$oracleversion = $matches[1];

// This is the query you want to "page" through
$sql = 'SELECT city, postal_code FROM locations ORDER BY city';

if (
$oracleversion >= 12) {
// Make use of Oracle 12c OFFSET / FETCH NEXT syntax
$sql = $sql . ' OFFSET :offset ROWS FETCH NEXT :numrows ROWS ONLY';
} else {
// Older Oracle versions need a nested query selecting a subset
// from $sql. Or, if the SQL statement is known at development
// time, consider using a row_number() function instead of this
// nested solution. In production environments, be careful to
// avoid SQL Injection issues with concatenation.
$sql = "SELECT * FROM (SELECT a.*, ROWNUM AS my_rnum
FROM (
$sql) a
WHERE ROWNUM <= :offset + :numrows)
WHERE my_rnum > :offset"
;
}

$offset = 0; // skip this many rows
$numrows = 5; // return 5 rows
$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";
}

// Output is:
// 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 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($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 上擁有 READ 權限。(GRANT READ on DIRECTORY <目錄名稱> TO <使用者>)否則,您會收到一個隱晦的錯誤。警告:OCILobFileOpen: ORA-22285: FILEOPEN 操作的目錄或檔案不存在於... 第 ... 行 ...
<BR>
建立 DIRECTORY 的使用者會自動被授予 READ WITH THE GRANT OPTION 權限。
junk at netburp dot com
24 年前
關於 rowid 的一些提示。

別忘了 Oracle 函式

「rowidtochar」和「chartorowid」

「select rowidtochar(rowid) as FOO from table ....」

當您想要在表單或連結中傳遞 rowid 時,這是
唯一的方法。
To Top