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:获取一行,作为数组的键的第一列[重复]的主要内容,如果未能解决你的问题,请参考以下文章

PHP PDO fetch() 详解

致命错误:未捕获的错误:不能使用 PDOStatement 类型的对象作为数组

PHP使用PDOStatement处理结果集

foreach循环php中的PDOStatement

PHP扩展PDO MySQL之PDOStatement::bindParam vs bindValue

PDOStatement 到 JSON [关闭]