web-dev-qa-db-ja.com

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";
};
_

結果をフェッチした後、array_map('current', $result)を使用せずに_PDO::FETCH_*_モードを使用して目的の結果セットを取得する方法はありますか?

25
HongKilDong

それはかなり古いトピックですが、私は非常に簡単な解決策を見つけました:

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

最初の列はキーとして設定され、残りは値として設定されます。

配列をウォークスルーしたり、array_mapを使用したりする必要はありません。

55

不要なネスト配列レベルを減らすには:

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

鍵連想配列

PDO::FETCH_GROUP|PDO::FETCH_UNIQUE|PDO::FETCH_ASSOC
11
Xakki

受け入れられた回答は、本質的に貨物カルトコードであり、偶然にのみ機能しますが、それ自体では意味がありません。

PDO::FETCH_GROUPおよびPDO::FETCH_UNIQUEは相互に排他的なフェッチモードであり、一緒に使用することはできません。そのうちの1つだけが機能します。それらを組み合わせると、後者が引き継ぎ、\PDO::FETCH_GROUP|\PDO::FETCH_UNIQUEは実際にはPDO::FETCH_UNIQUE

それ以外に、質問はそれ自体で曖昧であり、OPは配列に一意のフィールドによってindexedを付けることを望んでいますが、彼はそれをgrouping回答にも論争を巻き起こしました。

だからそれをまっすぐにするために:

  • toindex一意の値を持つ配列(一意の場合、結果の配列に従業員の名前でインデックスを付ける場合)、フェッチモードは PDO :: FETCH_UNIQUE

    $pdo->query('SELECT * FROM employee')->fetchAll(PDO::FETCH_UNIQUE);
    
  • groupの結果(たとえば、部署ごとに従業員をグループ化する場合)の場合、フェッチモードは PDO ::である必要があります。 FETCH_GROUP

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

どちらの場合も、最初のレベルの配列インデックスとして使用されるフィールドは、SELECTフィールドリストの最初にリストする必要があります。

PDO::FETCH_ASSOC。優先結果フォーマットのフェッチモードをコンストラクターで一度に設定できる場合、明示的にリストすることも意味がありません。

11

この回答は古くなっています。代わりに 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;
}
3
Charles

代わりにステートメントクラスを拡張することで、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();
2
mpen

なぜ誰も次の解決策を投稿していない理由はわかりませんが、それは私にとっては完璧に機能します:

PDO::FETCH_UNIQUE | PDO::FETCH_ASSOC

したがって、ステートメントを次のように変更します。

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

まさにあなたが望むものでなければなりません。

0
kojow7