請注意,所有 pg_fetch_* 函式都會忽略資料的原始類型,並一律返回字串。(數字也是如此)
(PHP 4 >= 4.3.0, PHP 5, PHP 7, PHP 8)
pg_fetch_assoc — 將一行擷取為關聯式陣列
pg_fetch_assoc() 會傳回一個對應於所擷取列 (紀錄) 的關聯式陣列。
pg_fetch_assoc() 等同於呼叫 pg_fetch_array() 並將 PGSQL_ASSOC
作為選用的第三個參數。它只會返回一個關聯式陣列。如果您需要數字索引,請使用 pg_fetch_row()。
注意:此函式會將 NULL 欄位設定為 PHP 的
null
值。
pg_fetch_assoc() 並不會比使用 pg_fetch_row() 慢很多,而且明顯更容易使用。
result
一個 PgSql\Result 實例,由 pg_query()、pg_query_params() 或 pg_execute()(以及其他函式)返回。
row
要擷取的結果集中列的編號。列從 0 開始編號。如果省略或為 null
,則會擷取下一列。
一個以欄位名稱作為索引的關聯式 陣列。陣列 中的每個值都以 字串 表示。資料庫中的 NULL
值會以 null
返回。
如果 row
超過集合中的列數、沒有更多列或發生任何其他錯誤,則返回 false
。
版本 | 說明 |
---|---|
8.1.0 | result 參數現在需要一個 PgSql\Result 實例;以前需要的是一個資源。 |
範例 #1 pg_fetch_assoc() 範例
<?php
$conn = pg_connect("dbname=publisher");
if (!$conn) {
echo "發生錯誤。\n";
exit;
}
$result = pg_query($conn, "SELECT id, author, email FROM authors");
if (!$result) {
echo "發生錯誤。\n";
exit;
}
while ($row = pg_fetch_assoc($result)) {
echo $row['id'];
echo $row['author'];
echo $row['email'];
}
?>
注意!如果您的查詢返回多個同名欄位,則結果陣列中只會包含最右邊的欄位。如果您使用聯結組合,這可能會導致問題。
例如
<?php
// 假設 'pkey' 是表格 a 和 b 的主鍵欄位(主鍵永遠不會是 null)
$res = pg_query("Select a.pkey, b.* FROM a LEFT JOIN b using (pkey)");
$data = pg_fetch_assoc($res);
var_dump($data['pkey']) // 實際上是 b.pkey,可能是 NULL!
?>
兩個表格都包含一個名為 'pkey' 的欄位。現在表格 'b' 位於 LEFT JOIN 的可選端,因此 b.pkey(透過 'b.*' 隱式包含)可能是 NULL。
當您使用 pg_fetch_assoc() 時,問題就出現了,有兩個名為 'pkey' 的欄位,但結果陣列每個鍵只能包含一個值——在這種情況下,它會選擇表格 B 中的值而不是表格 A 中的值,而且由於 B 位於左聯結的可選端,$data['pkey'] 可能是 NULL。因此,如果您期望從表格 A 中擷取該欄位,則需要使用不同的 pg_fetch() 或重寫您的查詢以避免歧義。
如果您在不同版本的 PHP 之間移動,這可能很方便
if (!function_exists('pg_fetch_assoc')) {
function pg_fetch_assoc ($result)
{
return @pg_fetch_array($result, NULL, PGSQL_ASSOC);
}
}
將 't' 和 'f' 轉換為 PHP 布林值
$result = pg_query($_db, $sql);
while ( $row = pg_fetch_assoc( $result ) )
{
fixBooleans($result, $row);
//其他程式碼
}
函式 fixBooleans($result, &$row)
{
for ($fld_i = 0; $fld_i < pg_num_fields($result); $fld_i++)
{
$fld_name = pg_field_name($result, $fld_i);
if( pg_field_type($result, $fld_i) == 'bool' )
{
if( $row[ $fld_name ] == 't' )
{
$row[ $fld_name ] = true;
}
elseif($row[ $fld_name ] == 'f')
{
$row[ $fld_name ] = false;
}
}
}
}
<html>
<head>
<script>
function waarde(){
var text = document.getElementById("optVakken").value;
document.getElementById("txthidden").value = text;
document.forms["hiddenform"].submit();
}
</script>
<?php
// 選擇所有教師的下拉式選單
function leerkrachten($aName){
include("includes/connect.php");
}
// 選擇所有科目的下拉式選單
function vakken($aID){
include("includes/connect.php");
$SelectVakkenQuery = "SELECT * FROM vakken";
$SelectVakkenResult = $mysqli->query($SelectVakkenQuery);
$Choice = "<select id='$aID' onchange=waarde()><option>請選擇科目</option>";
while($rij2 = $SelectVakkenResult->fetch_assoc()){
$VakID = $rij2['vakid'];
$Vaknaam = $rij2['voluit'];
$Choice .= "<option value='$VakID'>$Vaknaam</option>";
}
$Choice .= "</select>";
return $Choice;
}
?>
<title>補救教學練習</title>
</head>
<body>
<?php
include("includes/connect.php");
// 建立下拉式選單
// 第一個下拉式選單
echo vakken("optVakken")."<br><br>";
// 第二個下拉式選單
if(!isset($_POST['txthidden'])){
$SelectLeerkrachtenQuery = "SELECT * FROM leerkrachten";
$SelectLeerkrachtResult = $mysqli->query($SelectLeerkrachtenQuery);
$Choice = "<select>";
while($rij=$SelectLeerkrachtResult->fetch_assoc()){
$Voornaam = $rij['voornaam'];
$Naam = $rij['naam'];
$LKID = $rij['leerkrachtid'];
$Volledig = $Voornaam . " " . $Naam;
$Choice .= "<option value='$LKID'>$Volledig</option>";
}
$Choice .= "</select><br><br>";
echo $Choice;
}else{
$vakid = $_POST['txthidden'];
$SelectLeerkrachtenQuery = "SELECT * FROM leerkrachten JOIN leerkrachtpervak ON leerkrachten.leerkrachtid = leerkrachtpervak.leerkrachtid WHERE vakid = '$vakid'";
$SelectLeerkrachtResult = $mysqli->query($SelectLeerkrachtenQuery);
$Choice = "<select>";
while($row3=$SelectLeerkrachtResult->fetch_assoc()){
$Voornaam = $row3['voornaam'];
$Naam = $row3['naam'];
$Volledig = $Voornaam . " " . $Naam;
$Choice .= "<option>$Volledig</option>";
}
$Choice .= "</select><br><br>";
echo $Choice;
}
// 隱藏的 textbox 給 JS 使用
echo "<form method='post' id='hiddenform'><input type='hidden' name='txthidden' id='txthidden'></form>";
$mysqli->close();
?>
</body>
</html>
基於有限狀態機 (FSM) 的強大 pg_parse_array() 變體:適用於任何維度的 Postgres 陣列(其字串表示法必須格式良好),具備引號規則檢查,複雜度為 O(N),其中 N 是 Postgres 陣列字串表示法的長度。
<?php
define('STATE_BEGIN', 1);
define('STATE_INARRAY',2);
define('STATE_OUTARRAY', 3);
define('STATE_INSLASH', 4);
define('STATE_INQUOTES', 5);
function pg_parse_array($value) {
$resultArray = $indexArray = array(); $level = $index = 0;
$ptr = &$resultArray;
for($i = 0; $i < strlen($value); $i++){
switch($level){
case 1:
if($index > 0){
$ptr = & $ptr[sizeof($ptr)];
}
$indexArray[++$index] = & $ptr;
break;
case -1:
$ptr = & $indexArray[--$index];
break;
}
$level = processFSM($value{$i}, $ptr);
}
return $resultArray;
}
function processFSM($chr, &$result){
static $state = STATE_BEGIN, $index = 0;
$level = 0;
switch(true){
case $chr == '{' && in_array($state, array(STATE_BEGIN,STATE_INARRAY,STATE_OUTARRAY), true):
$state = STATE_INARRAY;
$index = 0;
$level = +1;
break;
case $chr == '}' && in_array($state, array(STATE_INARRAY,STATE_OUTARRAY), true):
$state = STATE_OUTARRAY;
$level = -1;
break;
case $chr == '\\' && $state !== STATE_BEGIN:
$state = $state === STATE_INSLASH ? STATE_INQUOTES : STATE_INSLASH;
break;
case $chr == '"' && !in_array($state, array(STATE_BEGIN,STATE_INSLASH), true):
$state = $state === STATE_INQUOTES ? STATE_INARRAY : STATE_INQUOTES;
break;
case $chr == ',' && in_array($state, array(STATE_INARRAY,STATE_OUTARRAY), true):
$index = sizeof($result);
break;
case $state !== STATE_BEGIN:
$state = $state === STATE_INSLASH ? STATE_INQUOTES : $state;
isset($result[$index]) or $result[$index] = '';
$result[$index] .= $chr;
break;
}
return $level;
}
?>
請注意,如果您的結果欄位之一是陣列,它將會以 '{value1,value2, ... }' 的通用格式輸出為字串,這與 postgres 處理 SQL 陣列的行為一致。
https://postgresql.dev.org.tw/docs/8.4/static/arrays.html#ARRAYS-IO
以下是一個將簡單(一維)SQL 陣列轉換為 PHP 陣列的函式:
<?php
function pg_parse_array($field)
/*
* Converts a simple SQL array field to its PHP equivalent. e.g:
*
* {null} --> Array(null);
* {"null"} --> Array("null");
* {foo,bar} --> Array("foo", "bar");
* {"foo,bar"} --> Array("foo,bar");
* {"Hello \"World\""} --> Array('Hello "World"');
*
*/
{
// NULL fields are always NULL
if (!is_string($field)) return $field;
// Check for curly braces which may indicate an SQL array field
if ($field[0] != '{' or substr($field, -1) != '}') return $field;
$field = trim(substr($field, 1, -1));
$array = Array();
// Break up the string into the following:
// - quoted text that MAY have special chars escaped by a backslash
// - unquoted text that may NOT have special chars
$search = '/(")?+((?(1)(?:\\\\.|[^"])*|[^,]+))(?(1)\\1)/';
preg_match_all($search, $field, $matches, PREG_SET_ORDER);
foreach($matches as $value)
{
if ($value[1])
{
// Quoted element, with backslash used to escape chars
$array[] = preg_replace('#\\\\(.)#', '$1', $value[2]);
}
else
{
// Unquoted element
$value[2] = trim($value[2]);
if (strtolower($value[2]) == 'null') $array[] = null; // NULL
else $array[] = $value[2];
}
}
return $array;
}
// Some tests to demonstrate this function
var_export(pg_parse_array('{null}'); // Output is Array(null);
var_export(pg_parse_array('{foo,bar}'); // Output is Array('foo', 'bar');
var_export(pg_parse_array('{"null"}'); // Output is Array('null');
?>
關於可選的 int 參數
請求結果集中不存在的行號是錯誤的。不要這樣做。
請事先使用 pg_num_rows() 檢查,或者使用預設行為,依序返回每一列,並在返回最後一列後返回 false;如果沒有返回任何列,則立即返回 false。
值得注意的是,當您查詢多個表格時,只會返回每個名稱的第一列。
也就是說,如果您連接兩個都具有名為 'name' 欄位的表格,您在陣列中只會收到一個名為 name 的欄位,它會對應到第一個表格中的那個欄位。
建議您在這種情況下永遠使用別名來區分您的欄位。
這裡有另一種方法可以用很少的程式碼迭代結果集並顯示所有欄位... 可能比 foreach 更快
<?php
print '<table>';
while($row=pg_fetch_assoc($rs2)) print '<tr><td>'.join('</td><td>',$row2).'</td></tr>';
print '</table>';
?>
$dbconn3 = pg_connect("host=127.0.0.1 port=5432 dbname=blah user=blah password=blah");
$result = pg_query($dbconn3, "SELECT * FROM Packages");
echo "<HTML><HEAD><TITLE>PostgreSQL 測試頁面</TITLE></HEAD><BODY>";
echo "<TABLE>";
$pkg = pg_fetch_assoc($result);
foreach ($pkg as $value) {
echo "<TR><TD>$value";
echo "</TR></TD>";
}
echo "</TABLE><P>";
echo "這個套件的完整檔名是: {$pkg['name']}-{$pkg['version']}{$pkg['extension']}";
echo "</BODY></HTML>";
對於產生表格,這個方法有效,而且我個人比較喜歡用 foreach() 而不是 while 迴圈,因為沒有意外造成無限迴圈的風險… foreach 只會在有東西可以處理的時候運作,然後就會停止。我覺得底部的 echo 指令也可能會派上用場… 我花了一點時間才發現這一點。
一個需要注意的重點 (從 PHP 4.3.2 開始)
如果您習慣使用「擴展」比較運算子 (=== 和 !==) 來讓程式碼更容易閱讀,當提供的資源句柄無效時,這個函式會返回 NULL(而不是 false)。例如:
$rs = @pg_query('SELECT * FROM fake_table');
while (false !== ($row = @pg_fetch_assoc($rs)))
{
print_r($row);
}
顯然,您應該在開始 while 迴圈之前檢查 $rs 是否 === false,但這個例子是用來說明如果 $rs 為 false 時,可能會出現無限迴圈的問題。
補充 Luke 關於 SQL 布林值的說明(這是我吃盡苦頭才學到的一件事),一個相對簡單的解決方法是在查詢內將布林值欄位強制轉換為整數,例如:
<?php
// 假設 'foo' 是表格中一個布林值類型的欄位
$res = pg_query("Select foo as foo1, foo::integer as foo2 from bar");
$data = pg_fetch_assoc($res);
if ($data['foo1']) echo 'foo1 = TRUE'; // 無法如預期運作(字串 't' 和字串 'f' 都會被評估為 TRUE)
if ($data['foo2']) echo 'foo2 = TRUE'; // 如預期運作(字串 '0' 會被評估為 FALSE)
?>