PHP PDOStatement:获取一行,作为数组的键的第一列[重复]
Posted
技术标签:
【中文标题】PHP PDOStatement:获取一行,作为数组的键的第一列[重复]【英文标题】:PHP PDOStatement: fetch a row, as the first column as the key of an array [duplicate] 【发布时间】:2010-11-26 03:09:39 【问题描述】:我正在使用PDOStatement
来查询数据库。每当我得到一个返回的行时,我希望它被提取到一个数组中,$row[0]
作为键,行中的后续元素作为值。
当然,我可以编写foreach
循环和if
条件的组合来完成这项工作,如下所示:
private static function GetmysqlResult($dbname, $sqlString)
$dbh = self::ConstructPDOObject($dbname);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$result=array();
foreach ($dbh->query($sqlString) as $row)
// the simplest case for 2 columns,
// should add more to handle more columns
$result[$row[0]][]=$row[1];
return $result;
但我正在寻找现有的方法;有没有这样的方法已经存在了?
为什么要重新提出问题。
这里问的显然是 PDO::FETCH_GROUP|PDO::FETCH_ASSOC 的组合。 PDO::FETCH_KEY_PAIR 仅适用于 2 列结果。但这里的示例是一个 2 列结果,仅用于简化问题中的代码,并非适用于所有情况。
【问题讨论】:
您的代码实际上对非唯一键上的行进行分组,这也是可能答案的要求吗? 我要求重开问题,因为测试了很多解决方案,这里问的显然是PDO::FETCH_GROUP|PDO::FETCH_ASSOC
的组合。 PDO::FETCH_KEY_PAIR 仅适用于 2 列结果。但是这里的示例是一个 2 列的结果,只是为了简化问题中的代码,而不是针对所有情况。
【参考方案1】:
学分归 devdRew。 Check the other question here.
显然,您可以按照答案中的说明进行操作。我也检查过,效果很好。
$q = $db->query("SELECT `name` AS name, `value` AS value FROM `settings`;");
$r = $q->fetchAll(PDO::FETCH_KEY_PAIR);
编辑
此答案要求您指定最多 2 列:1 个键和 1 个值。如果您需要从数据库中检索更多密钥,请查看下面的答案并阅读 @nullabilty
的评论。对于那些懒惰的人,这是他的方法:
$q->fetchAll(PDO::FETCH_UNIQUE);
【讨论】:
这是唯一使用第一列作为键的方法,如果您需要额外的列、CONCAT 或类似的额外字段作为第二列值的分隔字符串并使用explode
有一个数组在使用该值之前。
@nickl- 为此目的使用CONCAT
是一个可怕的想法;这个答案应该专门用于键值对,这是它的设计目的。
你要让赏金过期吗?
@Jack 可怕可能有点苛刻,你不觉得吗,尤其是在没有动力的情况下。也许这是我内心的叛逆,但我不喜欢被告知我不能做某事。也许是跳出框框思考,模糊了这之间的界限,这就是它的本意,这就是我可以用它做的。归根结底,ymmv,它正在用你可以支配的资源以最好的方式解决问题。剩下的就是自行车脱落,对底线几乎没有影响。
@nickl- 我想知道你会用什么分隔符? uniqid()
?此外,您还必须将现有查询重写为这种格式。老实说,我根本不明白。【参考方案2】:
$stmt->fetchAll(PDO::FETCH_UNIQUE);
虽然有点小技巧,但实际上是唯一的方法,因为有人 decided FETCH_KEY_PAIR 应该只需要 2 列结果集。
注意:第一列是key,不会以任何其他形式在结果集中返回。
【讨论】:
谢谢,我将我的扩展至PDO::FETCH_GROUP|PDO::FETCH_UNIQUE|PDO::FETCH_ASSOC
以获得我所需要的。
注意:第一列是key,不会以其他形式返回结果集中。你仍然可以使用“SELECT firstcolumn AS id, firstcolumn, secondcolumn ...”复制你的第一列,如果你想得到列是结果【参考方案3】:
Afaik,在 php 中没有现有的方法可以做到这一点,但有几种方法可以实现你想要的。
第一个是 Xeoncross 所说但稍作修改的内容:
$pdostmt = $pdo->query("SELECT ... FROM your_table");
$res = array();
foreach ($pdostmt->fetchAll(PDO::FETCH_ASSOC) as $row)
$res[array_shift($row)] = $row;
否则,您可以使用__set()
方法创建一个类来捕获变量赋值:
class at_res
public $key;
public $values = array();
protected $flag = true;
public function __set($var, $value)
if ($this->flag)
$this->key = $value;
$this->flag = false;
else
$this->values[$var] = $value;
public function extract()
return array($this->key => $this->values);
$pdo = new PDO(...);
$pdostmt = $pdo->query("SELECT ... FROM your_table");
$res = $pdostmt->fetchObject('at_res');
var_dump($res->extract());
希望对你有帮助。
【讨论】:
【参考方案4】:一些提示,您需要将正确的 fetch 样式传递给 PDOStatement->fetch() 方法,这样您就不会得到双重数据(数字和文本列名)。就像 $row[0] 和 $row['id'] 当你使用 PDO::FETCH_BOTH 时它们都包含相同的值。
$result = $dbh->query($sqlString);
while ($row = $result->fetch(PDO::FETCH_NUM))
...
至于您的问题,您必须获取所有结果,然后创建一个数组,其中 $row['id'] 作为键,结果行作为值 - 就像您正在做的那样。我围绕 PDO 构建了一个完整的 ORM 库,但我永远找不到任何东西可以自动执行此操作。
$result = $dbh->query($sqlString);
$results = array();
while ($row = $result->fetch(PDO::FETCH_NUM))
$results[$row[0]] = $row;
return $results;
【讨论】:
这与我们试图避免的使用 foreach 循环有何不同?【参考方案5】:除了两列表场景之外,在 PDO 级别没有什么可以处理这个问题,但是您可以为它编写一个可重用的迭代器,如下所示:
class FirstColumnKeyIterator implements Iterator
private $stmt;
private $key;
private $data;
private $mode;
public function __construct(PDOStatement $stmt, $fetch_mode = PDO::FETCH_NUM)
$this->stmt = $stmt;
$this->mode = $fetch_mode;
$this->fetch();
private function fetch()
if (false !== ($this->data = $this->stmt->fetch($this->mode)))
$this->key = current(array_splice($this->data, 0, 1));
public function rewind()
// nil operation
public function key()
return $this->key;
public function current()
return $this->data;
public function next()
$this->fetch();
public function valid()
return false !== $this->data;
构造函数采用PDOStatement
和可选的获取模式(默认为数字列,但可以将关联数组更改为PDO::FETCH_ASSOC
)并允许您使用典型的foreach
迭代查询结果。
使用示例:
$dbh = new PDO(/* etc */);
$stmt = $dbh->query('SELECT * FROM accounts');
foreach (new FirstColumnKeyIterator($stmt, PDO::FETCH_ASSOC) as $key => $value)
echo $key, ' = ', print_r($value, true), PHP_EOL;
【讨论】:
创造力 10 分 =) 但您会发现这种方式比原来的方案更昂贵。您可以通过首先引用new Iterator
来改进这一点,如果可以提供帮助,请始终避免使用as $key => #value
。您会发现,只要还引用了计数,在引用的 array_keys
上的 for 循环就会产生更好的结果。 for ($i = 0; $i < count($data); $i++)
将最强大的构造变成了有史以来最糟糕的循环,应该让我拿回我的钱。
@nickl 迭代器总是比“普通”数组更昂贵,因为在每个循环中都会执行额外的代码,这些代码不会通过引用实例而消失;删除key => value
也不是一种选择,因为否则无法获得密钥:)
使用迭代器并仍然获取密钥的替代方法可能是 do..while 或 while ,我可以想到几个 for 循环,即。 for ($it = new ArrayIterator($data); $it->valid(); $it->next()) echo $it->key() .' => '. $it->current();
但我相信你也想过这些。 =)
@nickl ArrayIterator 的问题是你必须先加载所有行,所以如果你有很多行,这可能是个问题:)以上是关于PHP PDOStatement:获取一行,作为数组的键的第一列[重复]的主要内容,如果未能解决你的问题,请参考以下文章
致命错误:未捕获的错误:不能使用 PDOStatement 类型的对象作为数组