Is there a way to fetch associative array grouped by the values of a specified column with PDO?

前端 未结 8 1391
轮回少年
轮回少年 2020-11-28 07:39

For example, let\'s use some simple data set

+---------+------+------+------------+
| name    | age  | sex  | position   |
+---------+------+------+---------         


        
相关标签:
8条回答
  • 2020-11-28 08:01

    This answer is out of date, please see this other answer instead.


    It looks like there's no way to do this as part of fetchAll.

    Your best bet is going to be creating a class that extends PDO, adding a utility method to it.

    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;
    }
    
    0 讨论(0)
  • 2020-11-28 08:06

    We can make Charles' solution a little nicer by extending the statement class instead:

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

    Usage:

    $users = $pcs->query("SELECT name, user_id, discipline_id FROM wx_user")->fetchKeyAssoc();
    
    0 讨论(0)
  • 2020-11-28 08:10

    Not sure why no one has posted the following solution, but it works perfectly for me:

    PDO::FETCH_UNIQUE | PDO::FETCH_ASSOC
    

    So, changing your statement to:

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

    should be exactly what you want.

    0 讨论(0)
  • 2020-11-28 08:12

    It's quite old topic, but I found very easy solution:

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

    First col will be set as key, rest will be set as value.

    No need to walk over the array or use array_map.

    0 讨论(0)
  • 2020-11-28 08:14

    The accepted answer is essentially a cargo cult code, that does its job only by accident, but makes no sense by itself.

    PDO::FETCH_GROUP and PDO::FETCH_UNIQUE are mutual exclusive fetch modes, that cannot be used together. Only one of them would work. When you combine them, the latter takes over and \PDO::FETCH_GROUP|\PDO::FETCH_UNIQUE is actually just PDO::FETCH_UNIQUE.

    Beside that, the question is ambiguous by itself, the OP wants his array to be indexed by the unique field, whereas he called it grouping which raised a controversy in the answers as well.

    So to make it straight:

    • to index an array with unique values (when you want the resulting array to be indexed by the employee's name, given they are unique), the fetch mode must be PDO::FETCH_UNIQUE:

      $pdo->query('SELECT name, e.* FROM employee e')->fetchAll(PDO::FETCH_UNIQUE);
      
    • to group the results (when you want to group employees by department, for example), the fetch mode must be PDO::FETCH_GROUP:

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

    in both cases the field to be used as the first level array index, must be listed first in the SELECT field list.

    A note on the PDO::FETCH_ASSOC. Given that fetch mode for the preferred result format could be set once for all in the constructor, it makes no sense to list it explicitly as well.

    0 讨论(0)
  • 2020-11-28 08:15

    to reduce a unnecessary nesting array level:

    $res = $pdo->query('SELECT * FROM employee')->fetchAll(PDO::FETCH_GROUP|PDO::FETCH_ASSOC);
    $res = array_map('reset', $res);
    
    0 讨论(0)
提交回复
热议问题