请注意,所有 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
由 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 的主键列(主键从不为空)
$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,可能为空!
?>
两个表都包含名为 'pkey' 的列。现在表 'b' 位于 LEFT JOIN 的可选侧,因此 b.pkey(通过 'b.*' 隐式包含)可能为空。
当您使用 pg_fetch_assoc() 时,会产生问题,有两个名为 'pkey' 的列,但结果数组每个键只能包含一个值 - 在这种情况下,它将选择表 B 中的值而不是表 A 中的值,并且由于 B 位于 LEFT JOIN 的可选侧,因此 $data['pkey'] 可能会为空。因此,如果您希望检索表 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);
// 其他代码
}
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);
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.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 Test Page</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 "This package's full filename is: {$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)
?>