Подтвердить что ты не робот

Есть ли способ получить ассоциативный массив, сгруппированный по значениям указанного столбца с PDO?

Например, допустим использование простого набора данных

+---------+------+------+------------+
| 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) после получения результатов?

4b9b3361

Ответ 1

Это довольно старая тема, но я нашел очень легкое решение:

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

Первый столбец будет установлен как ключ, остальные будут установлены как значение.

Не нужно ходить по массиву или использовать array_map.

Ответ 2

чтобы уменьшить ненужный уровень массива вложенности:

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

Ответ 3

Ключ-массив

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

Ответ 4

Этот ответ устарел, см. этот другой ответ.


Похоже, что нет возможности сделать это как часть 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

Мы можем сделать решение Чарльза немного лучше, расширив класс операторов:

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();