php 有没有一种方法可以用PDO获取按指定列的值分组的关联数组?

55ooxyrt  于 2022-12-21  发布在  PHP
关注(0)|答案(8)|浏览(111)

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

+---------+------+------+------------+
| 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)来获得所需的结果集呢?

zysjyyx4

zysjyyx41#

这是一个很老的主题,但我发现非常简单的解决方案:

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

第一列将设置为键,其余将设置为值。

无需遍历数组或使用array_map。

bqjvbblv

bqjvbblv2#

公认的答案基本上是一个“货物邪教代码”,它只是偶然地发挥作用,但本身没有意义。
PDO::FETCH_GROUPPDO::FETCH_UNIQUE互斥的fetch模式,不能一起使用。只有其中一个可以工作。如果你把它们组合在一起,后者会接管,\PDO::FETCH_GROUP|\PDO::FETCH_UNIQUE实际上就是PDO::FETCH_UNIQUE
此外,这个问题本身就模棱两可:OP希望得到的数组由唯一字段进行索引,而他们称之为分组,这在答案中也引起了争议。
所以说实话:

  • 索引具有唯一值的结果数组(当您希望按雇员的姓名索引数组时,假定它们是唯一的),获取模式必须是PDO::FETCH_UNIQUE:
$pdo->query('SELECT name, e.* FROM employee e')->fetchAll(PDO::FETCH_UNIQUE);
  • 要对结果进行分组(例如,当您希望按部门对员工进行分组时),获取模式必须为PDO::FETCH_GROUP:
$pdo->query('SELECT dept_id, e.* FROM employee e')->fetchAll(PDO::FETCH_GROUP);

在这两种情况下,用作第一级数组索引的字段必须首先列在SELECT字段列表中。
关于PDO::FETCH_ASSOC的一个注意事项。由于preferred fetch mode最好在PDO构造函数中设置一次,因此大多数情况下可以在这里省略。

7y4bm7vi

7y4bm7vi3#

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

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

qoefvg9y4#

键关联数组

PDO::FETCH_GROUP|PDO::FETCH_UNIQUE|PDO::FETCH_ASSOC
33qvvth1

33qvvth15#

此答案已过期,请参阅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;
}
bnl4lu3b

bnl4lu3b6#

看起来没有人提到过这种变化,所以,为了未来的谷歌人的利益:
合并\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

lawou6xi

lawou6xi7#

我们可以通过扩展语句类来使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();
lp0sw83n

lp0sw83n8#

不知道为什么没有人发布下面的解决方案,但它对我来说非常有效:

PDO::FETCH_UNIQUE | PDO::FETCH_ASSOC

因此,将您的声明更改为:

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

应该就是你想要的。

相关问题