有没有办法获取按PDO指定列的值分组的关联数组?

时间:2011-03-19 11:17:55

标签: php arrays pdo fetch

例如,让我们使用一些简单的数据集

+---------+------+------+------------+
| name    | age  | sex  | position   |
+---------+------+------+------------+
| Antony  |   34 | M    | programmer |
| Sally   |   30 | F    | manager    |
| Matthew |   28 | M    | designer   |
+---------+------+------+------------+

我们想要获得的是以这种方式组织的阵列

Array
(
  [Antony] => Array
    (
      [age] => 34
      [sex] => M
      [position] => programmer
    )

  [Sally] => Array
    (
      [age] => 30
      [sex] => F
      [position] => manager
    )

  [Matthew] => Array
    (
      [age] => 28
      [sex] => M
      [position] => designer
    )
)

作为粗略的近似,我们可以使用

$pdo->query('SELECT * FROM employee')->fetchAll(PDO::FETCH_GROUP|PDO::FETCH_ASSOC);

但结果我们有不必要的嵌套级别

Array
(
    [Antony] => Array
        (
            [0] => Array
                (
                    [age] => 34
                    [sex] => M
                    [position] => programmer
                )

        )

    [Sally] => Array
        (
            [0] => Array
                (
                    [age] => 30
                    [sex] => F
                    [position] => manager
                )

        )

    [Matthew] => Array
        (
            [0] => Array
                (
                    [age] => 28
                    [sex] => M
                    [position] => designer
                )

        )

)

我试图通过使用回调函数

来摆脱这种不必要的嵌套级别
$stmt->fetchAll(PDO::FETCH_GROUP|PDO::FETCH_ASSOC|PDO::FETCH_FUNC, 'current');

但由于某些原因,它没有通过

Array
  (
   [0] => Array
    (
        [age] => 34
        [sex] => M
        [position] => programmer
    )
  ) 

但是只有一堆标量34, 'M', 'programmer'来回调函数:(

您可以使用回调

这样的功能来查看它
function what_do_you_pass_me() {

  $numargs = func_num_args();
  $arg_list = func_get_args();
  for ($i = 0; $i < $numargs; $i++) {
    echo "Argument $i is: " . $arg_list[$i] . "\n";
  };
  echo "\n\n";
};

有没有办法在获取结果后使用PDO::FETCH_*模式获取所需的结果集而不使用array_map('current', $result)

8 个答案:

答案 0 :(得分:51)

这是一个相当古老的话题,但我找到了非常简单的解决方案:

->fetchAll(\PDO::FETCH_GROUP|\PDO::FETCH_UNIQUE)

第一个col将被设置为键,rest将被设置为值。

无需遍历数组或使用array_map。

答案 1 :(得分:13)

减少不必要的嵌套数组级别:

$res = $pdo->query('SELECT * FROM employee')->fetchAll(PDO::FETCH_GROUP|PDO::FETCH_ASSOC);
$res = array_map('reset', $res);

答案 2 :(得分:11)

Key assoc array

PDO::FETCH_GROUP|PDO::FETCH_UNIQUE|PDO::FETCH_ASSOC

答案 3 :(得分:9)

接受的答案基本上是货物崇拜代码,它只是偶然发挥作用,但本身没有任何意义。

PDO::FETCH_GROUPPDO::FETCH_UNIQUE是互斥式提取模式,不能一起使用。只有其中一个可以工作。合并后,后者接管,\PDO::FETCH_GROUP|\PDO::FETCH_UNIQUE实际上只是PDO::FETCH_UNIQUE

除此之外,问题本身是模糊的,OP希望他的数组被唯一字段索引,而他称之为分组引发了争议答案也是如此。

所以说实话:

  • 索引一个具有唯一值的数组(如果您希望生成的数组按员工的名称编制索引,因为它们是唯一的),则获取模式必须为 PDO::FETCH_UNIQUE

    $pdo->query('SELECT * FROM employee')->fetchAll(PDO::FETCH_UNIQUE);
    
  • 分组结果(例如,当你想按部门分组员工时),获取模式必须是 PDO::FETCH_GROUP

    $pdo->query('SELECT * FROM employee')->fetchAll(PDO::FETCH_GROUP);
    

在这两种情况下,必须首先在SELECT字段列表中列出要用作第一级数组索引的字段。

关于PDO::FETCH_ASSOC的说明。鉴于首选结果格式的获取模式可以在构造函数中为所有结果设置一次,因此将其明确列出也没有意义。

答案 4 :(得分:3)

此答案已过期,请参阅this other answer


看起来没有办法在fetchAll中执行此操作。

你最好的选择是创建一个扩展PDO的类,为它添加一个实用工具方法。

public function queryKeyedAssoc($query, $params, $key) {
    $sth = $this->prepare($query);
    $sth->execute($params);
    $res = array();
    while($row = $sth->fetch(PDO::FETCH_ASSOC))
        $res[ $row[$key] ] = $row;
    return $res;
}

答案 5 :(得分:2)

我们可以通过扩展语句类来改善Charles的解决方案:

class MyPdo extends PDO {
    function __construct($host, $database_name, $username, $password, $options=array()) {
        $options = self::merge(array(
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
            PDO::ATTR_STATEMENT_CLASS => array('PdoPlusStatement', array()),
            PDO::ATTR_EMULATE_PREPARES => true,
            PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8',
        ), $options);
        $dsn = "mysql:host=$host;dbname=$database_name;charset=utf8";
        parent::__construct($dsn, $username, $password, $options);
    }
}

class PdoPlusStatement extends PDOStatement {
    protected function __construct() {}

    /**
     * @param array|mixed $input_parameters An array of values with as many elements as there are bound parameters in the SQL statement being executed, or one or more non-array arguments to be matched with sequential parameter markers.
     * @throws PDOException
     * @return PdoPlusStatement
     */
    public function execute($input_parameters=null) {
        $args = func_get_args();
        $argc = func_num_args();
        if($argc===0) {
            parent::execute();
        } else {
            if($argc===1 && is_array($args[0])) {
                $args = $args[0];
            }
            parent::execute($args);
        }
        return $this;
    }

    /**
     * Returns an array containing all of the remaining rows in the result set
     * @return array An associative array using the first column as the key, and the remainder as associative values
     */
    public function fetchKeyAssoc() {
        return array_map('reset', $this->fetchAll(PDO::FETCH_GROUP|PDO::FETCH_ASSOC));
    }
}

用法:

$users = $pcs->query("SELECT name, user_id, discipline_id FROM wx_user")->fetchKeyAssoc();

答案 6 :(得分:1)

似乎没有人提到过这种变化,因此,为了将来的Google员工的利益:

合并\PDO::FETCH_GROUP\PDO::FETCH_COLUMN标志。这大大简化了我的SQL语句,并返回了我想要的确切结果集。它也很快。

$this->database->query('SELECT t.fk, t.id FROM my_table t ORDER BY t.fk ASC, t.id ASC')
  ->fetchAll(\PDO::FETCH_GROUP|\PDO::FETCH_COLUMN);

t.fkt.id有一对多关系。

我不必担心GROUP BY语句或MySQL对多个字段的分组处理的挑剔。最重要的是,我收到了以下形式的结果:

[
  foreign_key_1 => [
    0 => 11111,
    1 => 22222,
    2 => 33333,
  ],
  foreign_key_2 => [
    0 => 44444,
    1 => 55555,
    2 => 66666,
  ],
  foreign_key_3 => [
    0 => 77777,
    1 => 88888,
    2 => 99999,
  ],
];

而不是:

[      
  foreign_key_1 => [
    0 => [
      id => 11111,
    ],
    1 => [
      id => 22222,
    ],
    2 => [
      id => 33333,
    ],
  ],
  foreign_key_2 => [
    0 => [
      id => 44444,
    ],
    1 => [
      id => 55555,
    ],
    2 => [
      id => 66666,
    ],
  ],
  foreign_key_3 => [
    0 => [
      id => 77777,
    ],
    1 => [
      id => 88888,
    ],
    2 => [
      id => 99999,
    ],
  ],

];

希望它可以帮助某个人!


以供参考:https://phpdelusions.net/pdo/fetch_modes

答案 7 :(得分:0)

不确定为什么没有人发布以下解决方案,但它对我来说非常有用:

PDO::FETCH_UNIQUE | PDO::FETCH_ASSOC

所以,将你的陈述改为:

$pdo->query('SELECT * FROM employee')->fetchAll(PDO::FETCH_UNIQUE|PDO::FETCH_ASSOC);

应该是你想要的。