PHP Conference Japan 2024

odbc_fetch_array

(PHP 4 >= 4.0.2, PHP 5, PHP 7, PHP 8)

odbc_fetch_array將結果列擷取為關聯式陣列

說明

odbc_fetch_array(Odbc\Result $statement, ?int $row = null): array|false

從 ODBC 查詢中擷取關聯式 陣列

參數

statement

來自 odbc_exec() 的 ODBC 結果物件。

row

選擇性地選擇要擷取的列號。

回傳值

返回對應於擷取列的陣列,如果沒有更多列,則返回 false

更新日誌

版本 說明
8.4.0 statement 現在需要 Odbc\Result 實例;先前需要的是 資源
8.4.0 row 現在可以為 null。

注意事項

注意 此函數在使用 DBMaker、IBM DB2 或 UnixODBC 支援編譯時存在。

參見

新增註解

使用者貢獻的註解 15 則註解

16
russ at russprince dot com
20 年前
我非常喜歡 Ryan 的範例,所以我更進一步,新增了一個記錄集類別來搭配連線類別使用。我也對原始程式碼進行了略微的修改。另請注意,記錄集類別利用了 php5 的 __get 屬性函式...

<%
class odbcRecordset {
var $recordcount; // 記錄計數
var $currentrow; // 目前列
var $eof; // 是否已到檔案結尾

var $recorddata; // 記錄資料
var $query; // 查詢

function odbcConnection(){ // 應為 odbcRecordset 建構函式
$this->recordcount = 0;
$this->recorddata = 0;
}

function SetData( $newdata, $num_records, $query ) { // 設定資料
$this->recorddata = $newdata;
$this->recordcount = $num_records;
$this->query = $query;
$this->currentrow = 0;
$this->set_eof();
}

function set_eof() { // 設定檔案結尾旗標
$this->eof = $this->currentrow >= $this->recordcount;
}

function movenext() { if ($this->currentrow < $this->recordcount) { $this->currentrow++; $this->set_eof(); } } // 移至下一列
function moveprev() { if ($this->currentrow > 0) { $this->currentrow--; $this->set_eof(); } } // 移至上一列
function movefirst() { $this->currentrow = 0; $this->set_eof(); } // 移至第一列
function movelast() { $this->currentrow = $this->recordcount - 1; $this->set_eof(); } // 移至最後一列

function data($field_name) { // 取得資料
if (isset($this->recorddata[$this->currentrow][$field_name])) {
$thisVal = $this->recorddata[$this->currentrow][$field_name];
} else if ($this->eof) {
die("<B>錯誤!</B> 已到達記錄集的結尾"); // 錯誤訊息已翻譯
} else {
die("<B>錯誤!</B> 在來自查詢的目前記錄集中找不到欄位 <B>" . $field_name . "</B>:<br><br>$this->query"); // 錯誤訊息已翻譯
}

return $thisVal;
}

function __get($field_name) { // 魔術方法,用於直接存取欄位
return $this->data($field_name);
}
}

class odbcConnection {
var $user; //資料庫的使用者名稱
var $pass; //密碼

var $conn_handle; //連線控制代碼
var $temp_fieldnames; //用於儲存欄位名稱的暫存陣列,讓剖析返回的資料更容易。

function odbcConnection(){ // 應為 odbcRecordset 建構函式
$this->user = "";
$this->pass = "";
}

function open($dsn,$user,$pass){
$handle = @odbc_connect($dsn,$user,$pass,SQL_CUR_USE_ODBC) or
die("<B>錯誤!</B> 無法連線到資料庫。錯誤碼: ".odbc_error());
$this->conn_handle = $handle;
return true;
}

function &execute($query){
//建立一個暫存的記錄集
$newRS = new odbcRecordset;
$thisData = "";

$res = @odbc_exec($this->conn_handle,$query) or
die("<B>錯誤!</B> 無法執行查詢:<br><br>" . $query . "<br><br>錯誤碼: ".odbc_error());
unset($this->temp_fieldnames);

$i = 0;
$j = 0;
$num_rows = 0;

// 僅填入 select 查詢的結果
if (stripos($query, 'select ') !== false) {
while(odbc_fetch_row($res)) {
$num_rows++;

//建立暫存陣列
for ($j = 1; $j <= odbc_num_fields($res); $j++) {
$field_name = odbc_field_name($res, $j);
$this->temp_fieldnames[$j] = $field_name;
$ar[$field_name] = odbc_result($res, $field_name) . "";
}

$thisData[$i] = $ar;
$i++;
}
}

//填入記錄集並返回
$newRS->SetData( $thisData, $num_rows, $query );
return $newRS;
}
}
%>

用法很簡單

<%
$con = new odbcConnection
$con->open("dsn","user","pass")

$sql = "select bar from foo";
$rs = $con->execute($sql);

if (!$rs->eof) {
print $rs->data("bar");
// 或者 //
print $rs->bar;
}

while (!$rs->eof) {
// 一些程式碼
$rs->movenext();
}
%>

運作良好,但我還沒徹底測試過。
程式碼可以從這裡下載

http://www.russprince.com/odbc_functions.zip

致禮,
Russ
7
Ryan (rystar_x2000 at hotmail dot com)
20 年前
嗨,

在對 odbc_num_rows() 函式進行了很多調整,並嘗試讓 odbc_fetch_array() 與它良好搭配後,我決定編寫這個小函式,它將返回一個二維陣列,格式為 [列號][欄位]。

「列號」陣列索引顯然是儲存在陣列中的列號。
「欄位」索引對應於該列上的欄位名稱。

--函式--
<?

function fetch2DArray($res){
$i = 0;
$j = 0;
$toReturn = "";

while(odbc_fetch_row($res))
{
for ($j = 1; $j <= odbc_num_fields($res); $j++)
{
$field_name = odbc_field_name($res, $j);
$ar[$field_name] = odbc_result($res, $field_name);
}

$toReturn[$i] = $ar;
$i++;
}
return $toReturn;
}
?>

然後我更進一步... 並編寫了一個完整的類別來處理 odbc 連線... 它有點粗糙,但運作良好。

-- 類別 --
<?
class odbcConnection{
var $user; //資料庫的使用者名稱
var $pass; //密碼
var $conn_handle; //連線控制代碼
var $temp_fieldnames; //用於儲存欄位名稱的暫存陣列,讓剖析返回的資料更容易。

function odbcConnection(){ // 應為 odbcRecordset 建構函式
$this->user = "";
$this->pass = "";
}

function connectDatabase($dsn_link,$user,$pass){
$handle = @odbc_connect($dsn_link,$user,$pass,SQL_CUR_USE_DRIVER) or die("<B>錯誤!</B> 無法連線到資料庫。錯誤碼: ".odbc_error());
$this->conn_handle = $handle;
return true;
}

function runStoredQuery($query, $returns_results){

if($returns_results == false){
return false;
}

$toReturn = "";
$res = @odbc_exec($this->conn_handle, "exec ".$query."") or die("<B>錯誤!</B> 無法執行預存程序。錯誤碼: ".odbc_error());
unset($this->temp_fieldnames);
$i = 0;
$j = 0;

while(odbc_fetch_row($res))
{
//建立暫存陣列
for ($j = 1; $j <= odbc_num_fields($res); $j++)
{
$field_name = odbc_field_name($res, $j);
$this->temp_fieldnames[$j] = $field_name;
$this->temp_fieldnames[$j];
$ar[$field_name] = odbc_result($res, $field_name);
}

$toReturn[$i] = $ar;
$i++;
}

return $toReturn;
}

function runSQL($query,$returns_results){
$toReturn = "";

$res = @odbc_exec($this->conn_handle,$query) or die("<B>錯誤!</B> 無法執行查詢。錯誤碼: ".odbc_error());
unset($this->temp_fieldnames);
if($returns_results == false){
return false;
}

$i = 0;
$j = 0;

while(odbc_fetch_row($res))
{
//建立暫存陣列
for ($j = 1; $j <= odbc_num_fields($res); $j++)
{
$field_name = odbc_field_name($res, $j);
$this->temp_fieldnames[$j] = $field_name;
$ar[$field_name] = odbc_result($res, $field_name);
}

$toReturn[$i] = $ar;
$i++;
}

return $toReturn;
}


}

//以及如何使用這個類別的範例

include("dbClass.inc"); //其中 dbClass.inc 是包含此類別的檔案名稱

//宣告此類別的新實例
$dbConnection = new odbcConnection;

$dsn = "GroupWork"; //您的系統 DSN 名稱,指向您的資料庫
$dbConnection->connectDatabase($dsn,"",""); //無使用者名稱和密碼 - 唯讀存取

echo "<BR><HR><B>測試 SQL</b><BR><BR>";
$query_result = $dbConnection->runSQL("SELECT * FROM Event WHERE Type = 'Sport' ORDER BY EDate ASC",true);

if(!$query_result)
{
//無結果 - 您的錯誤代碼在此
}else{
//取得結果
$key = $dbConnection->temp_fieldnames;
$rows = count($query_result);
$keys = count($key);
$i = 0;


while($i < $rows){
$j = 1;
echo "印出第 $i 列:<BR>";

while($j < $keys - 1){

//$query_result[列][欄位];
$result = $query_result[$i][$key[$j]];
$field = $key[$j];
echo("欄位 <b>'".$field."'</b> : ".$result." <BR>");

$j++;
}
echo "<BR>----<BR><BR>";
$i++;
}
}
?>

希望這有所幫助。如果有人對這個類別有任何改進,請告訴我。
0
eion at robbmob dot com
2 年前
根據您連線的 ODBC 驅動程式,如果某列含有損毀的資料(例如錯誤的二進位資料或無效的地區設定資料),此函式也可能傳回「false」。在這些情況下,後續呼叫 odbc_fetch_array() 仍會傳回結果。

請使用 odbc_num_rows() 函式比較擷取的列數(如果驅動程式提供此類資料),或在 while 迴圈中確認失敗的列之後沒有額外的資料。

<?php
// 允許最多連續兩列錯誤/損毀的資料
while(($row = odbc_fetch_array($res)) || ($row = odbc_fetch_array($res)) || ($row = odbc_fetch_array($res))) {
var_dump($row);
}
?>

在使用 PHP 的 ODBC 與 Informix 和 Foxpro 資料庫通訊時,曾觀察到這種情況。
0
James Auxier
15 年前
在 SUSE 上透過 ODBC/freeTDS 層對啟用 ODBC 游標的持續性連線上的 MS SQL Server 嘗試同時查詢時,發現了一些有趣的行為。在 while 迴圈中使用 odbc_fetch_array() 逐步執行第一個資源會如預期般運作,但在該迴圈內呼叫後續建立的資源卻無法傳回資料,而 MySQL 等效指令碼卻能正常運作。

我發現,在每個 odbc_exec() 之後立即新增一個 num_rows 函式呼叫 [自訂函式,僅逐步執行結果集...odbc_num_rows() 的錯誤行為是另一個問題],然後重設游標,似乎可以快取結果以確保多個作用中結果集的正常效能。它可能比 MySQL 等效指令碼略慢,但至少它可以運作。
0
luke at croslow dot com
17 年前
在 IBM DB2 for iSeries 上,我必須指定要擷取的特定列號。如果我沒有指定列號,則行為會不穩定。

這似乎有效

<?php
for($i=1;$row=odbc_fetch_row($result,$i);$i++) {
//使用 $row
}
?>

列數必須從 1 開始,否則行為似乎未定義;也就是說,當我從 0 開始時,某些列可能會被返回兩次或更多次,或者根本不會返回。
0
robincw at gnospammail dot com
17 年前
我正在使用 MS SQL Server 2005,並使用帶有 SQL_CUR_USE_ODBC 的 odbc_connect。

我使用 odbc_fetch_array 從返回文字欄位的預存程序獲取結果時遇到問題。我收到的誤導性錯誤是

odbc_fetch_array() [function.odbc-fetch-array]: SQL 錯誤: [Microsoft][ODBC Cursor Library] 結果集不是由 SELECT 語句產生,SQL 狀態 SL004 in SQLGetData

最終,我發現通過將資料庫中的文字欄位轉換為 varchar(8000),它可以正常工作。也許使用 CONVERT 或 CAST 也可能有效。我還發現 varchar(max) 欄位會被弄亂。
0
tim at tmcode dot com
19 年前
根據您使用的 odbc 驅動程式/作業系統,odbc_fetch_array 可能未定義。(例如,如果您使用 --with-custom-odbc,您可能很不走運)。如果 odbc_fetch_array 函式尚不存在,可以安全地新增以下內容來定義它。與這裡提供的其他一些範例不同,這個範例將建立數值鍵和文字鍵。這個函式肯定不是非常理想,因為每次提取一行時都必須檢查欄位數和欄位名稱。通常您會迴圈處理結果集,並且無需每次都提取此資訊。它可以透過快取這些函式的結果來改進,但我將其留給其他人作為練習... :)

if(!function_exists("odbc_fetch_array"))
{

function odbc_fetch_array($res)
{
// 確保在沒有列時返回 false
if(!odbc_fetch_row($res)) return false;

$row=array();

// 填充列陣列
$numfields=odbc_num_fields($res);
for($i=1; $i<=$numfields; $i++)
{
//odbc 的索引從 1 開始,但由於我
// 正在嘗試模擬其他資料庫的 *_fetch_array 的功能
//(例如 mysql),我將減少我的
// 數值索引 1。這可能不是您想要的
// 在這種情況下,請刪除 -1
$row[odbc_field_name($res,$i)]=$row[$i-1]=odbc_result($res,$i);

}
return $row;
}


}
0
philip
19 年前
此函式需要存在以下其中一項:Windows、DB2 或 UNIXODBC。
0
powerstat at web dot de
20 年前
這個函式實作得很糟糕,因為所有其他資料庫的 fetch_array 版本都將值儲存為關聯式和數值鍵。
這個只儲存為關聯式鍵 :(
真的應該有人清理整個資料庫 API 設計!
-1
michael dot buergi at zhdk dot ch
16 年前
我使用 ODBC 連線到 MSSQL 2000 資料庫。只要我開啟了 ansi_warnings,在使用 odbc_fetch_array 或 odbc_fetch_row 和 odbc_result 擷取記錄時,偶爾會拿到兩次最後一筆記錄。
-1
xhat at NOSPAM dot hotmail dot com
20 年前
這是一個快速但不夠嚴謹的方法來完成同樣的事情

<?
while(odbc_fetch_row($result)) {
$var1 = odbc_result($result, "NAMEOFFIELD1");
$var2 = odbc_result($result, "NAMEOFFIELD2");
..... //根據欄位數量,設定對應的變數來儲存資料

$array_of_results[] = compact('var1', 'var2','var3', etc, etc)
}
?>

只需將每一行返回的資料轉換成變數,然後使用 compact() 函式。它會將每個變數名稱轉換為鍵,并将變數值轉換為陣列值。這樣可以建立一個很棒的二維陣列,您可以輕鬆地遍歷它,並且仍然可以使用鍵值來獲取資料。
-2
miles at e-clipseconsulting dot com
19 年前
回應 Sena 的貼文,odbc_num_rows 並非總是返回列數。在 MS Access 上執行查詢時,它似乎返回 -1 的列數。

<?php

while(odbc_num_rows($myodbcexec)){
$myarray[] = odbc_fetch_array($myodbcexec);
}

?>

在嘗試執行此程式碼時需要注意這一點。

Miles Phillips
e-Clipse Consulting
-2
bryant at zionprogramming dot com
16 年前
我發現 jezndiatyahoodotcodotuk 提供的函式非常有幫助。我使用的是 PHP 5.2.5,而這個函式並未被定義,所以它可能取決於所使用的 ODBC 驅動程式。

已發佈解決方案的唯一問題是,返回值與文件中指定的返回值不符。我做了以下修改,以便無論函式是否存在於內部,其都能以相同的方式運作

<?php
if (!function_exists('odbc_fetch_array')) {
function
odbc_fetch_array($result, $rownumber=null) {
$array = array();
if (!(
$cols = odbc_fetch_into($result, $result_array, $rownumber))) {
return
false;
}
for (
$i = 1; $i <= $cols; $i++) {
$array[odbc_field_name($result, $i)] = $result_array[$i - 1];
}
return
$array;
}
}

?>
-4
dinchu at gmail dot com
10 年前
我在使用 PHP 的 ODBC 函式時發現一個問題。當查詢包含 JOIN 且連接的表格具有相同欄位名稱時,即使該欄位未包含在選取欄位中,odbc_fetch_array 和 odbc_fetch_object 也會失敗(使用 SQL SERVER)。

這個問題只在使用 SQL_CUR_USE_ODBC 時才會發生。

例如:

$con = odbc_connect("Driver={SQL Server Native Client 11.0};Server=$serverName;Database=$db;", 'user', 'pass',SQL_CUR_USE_ODBC);

$query="SELECT table1.field1, table1.field2 from table1 JOIN table2 ON table1.field1=table2.field1";

$result = odbc_exec($con,$query);

$a=odbc_fetch_array($result);
上述程式碼會產生警告:

警告:odbc_fetch_array() [function.odbc-fetch-array]: SQL 錯誤: [Microsoft][SQL Server Native Client 10.0][SQL Server]欄位名稱 '' 模稜兩可。, SQL 狀態 37000 in SQLGetData

如果我在選取 field1 時沒有指定表格名稱,出現這個錯誤是可以理解的,但即使明確指定了表格名稱,它仍然無法正常運作。目前我找到的唯一「解決方法」是從選取的欄位中移除該欄位,或更改第二個表格中的欄位名稱。

我嘗試過的環境:SQL Server Native Client 10.0 和 SQL Server Native Client 11.0,SQL Server 2008,Windows 上的 PHP 5.3.2

備註:如果有人有任何不使用 sqlsrv 或 mssql 擴充功能的解決方案,那就太好了。
-4
Remy
19 年前
我使用以下函式將我的記錄集放入陣列中,它非常易於使用。

function dbquery($sql) {
$arr = array();
$conn = odbc_connect('dsn','user','pass');
$rs = odbc_exec($conn,$sql);
$x = 1;
while (odbc_fetch_row($rs)) {
for ($y = 1; $y <= odbc_num_fields($rs); $y++)
$arr[$x][$y] = odbc_result($rs,$y);
$x++;
}
if ($x > 1)
return $arr;
}

使用方法:

$arr=dbquery("SELECT * FROM tblTable");
echo $arr[1][1] // 顯示第一列的第一個欄位
To Top