请注意,所有 pg_fetch_* 函数都忽略数据的原始类型,并且始终返回字符串。(数字也是如此)
(PHP 4 >= 4.3.0, PHP 5, PHP 7, PHP 8)
pg_fetch_assoc — 读取一行作为关联数组
pg_fetch_assoc() 返回与获取的行(记录)对应的关联数组。
pg_fetch_assoc() 等效于以 PGSQL_ASSOC
作为可选的第三个参数调用 pg_fetch_array()。它只返回一个关联数组。如果需要数字索引,请使用 pg_fetch_row()。
注意: 此函数将 NULL 字段设置为 PHP
null
值。
pg_fetch_assoc() 并不比使用 pg_fetch_row() 慢很多,并且使用起来更加方便。
result
由 pg_query(),pg_query_params() 或 pg_execute()(以及其它函数)返回的 PgSql\Result 实例。
row
要获取的结果中的行号。行号从 0 向上编号。如果省略或为 null
,则获取下一行。
一个按关联方式(按字段名)索引的 array。 array 中的每个值都表示为 string。数据库 NULL
值作为 null
返回。
如果 row
超出集合中的行数,没有更多行或发生任何其他错误,则返回 false
。
版本 | 说明 |
---|---|
8.1.0 | result 参数现在需要一个 PgSql\Result 实例;以前,需要一个 资源(resource)。 |
示例 #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);
//some other code
}
function 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;
}
// 用于JS的隐藏文本框
echo "<form method='post' id='hiddenform'><input type='hidden' name='txthidden' id='txthidden'></form>";
$mysqli->close();
?>
</body>
</html>
这是一个更强大的基于有限状态机的 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);
/**
* 将 PostgreSQL 数组字符串解析为 PHP 数组
*
* @param string $value 要解析的 PostgreSQL 数组字符串
* @return array 解析后的 PHP 数组
*/
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;
}
/**
* 有限状态机 (FSM) 处理函数
*
* @param string $chr 当前字符
* @param array $result 结果数组的引用
* @return int 层级变化值
*/
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;
}
?>
请注意,如果您的某个结果字段是一个数组,它将按照 Postgres 处理 SQL 数组的方式,以 '{value1,value2, ... }' 的通用格式输出为字符串。
https://postgresql.ac.cn/docs/8.4/static/arrays.html#ARRAYS-IO
因此,这里提供了一个将简单(一维)SQL 数组转换为 PHP 数组的函数。
<?php
function pg_parse_array($field)
/*
* 将简单的 SQL 数组字段转换为其 PHP 等效形式。例如:
*
* {null} --> Array(null);
* {"null"} --> Array("null");
* {foo,bar} --> Array("foo", "bar");
* {"foo,bar"} --> Array("foo,bar");
* {"Hello \"World\""} --> Array('Hello "World"');
*
*/
{
// NULL 字段始终为 NULL
if (!is_string($field)) return $field;
// 检查可能表示 SQL 数组字段的花括号
if ($field[0] != '{' or substr($field, -1) != '}') return $field;
$field = trim(substr($field, 1, -1));
$array = Array();
// 将字符串分解为以下内容:
// - 可能包含用反斜杠转义的特殊字符的带引号文本
// - 可能不包含特殊字符的无引号文本
$search = '/(")?+((?(1)(?:\\\\.|[^"])*|[^,]+))(?(1)\\1)/';
preg_match_all($search, $field, $matches, PREG_SET_ORDER);
foreach($matches as $value)
{
if ($value[1])
{
// 带引号的元素,使用反斜杠转义字符
$array[] = preg_replace('#\\\\(.)#', '$1', $value[2]);
}
else
{
// 无引号的元素
$value[2] = trim($value[2]);
if (strtolower($value[2]) == 'null') $array[] = null; // NULL
else $array[] = $value[2];
}
}
return $array;
}
// 一些演示此函数的测试
var_export(pg_parse_array('{null}'); // 输出为 Array(null);
var_export(pg_parse_array('{foo,bar}'); // 输出为 Array('foo', 'bar');
var_export(pg_parse_array('{"null"}'); // 输出为 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)
如果您习惯使用“扩展”比较运算符(=== 和 !==)来尝试使您的代码在视觉上更易于理解,则如果提供的资源句柄无效(与 false 相反),此函数将返回 NULL。即:
$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)
?>