PHP PDO Fetch como array multidimensional com a primeira coluna como chave, e a segunda e terceira como par de valor-chave [duplicado]
Eu tenho uma tabela de banco de dados MySQL que é criada assim
CREATE TABLE table1 (
column1 varchar(50),
column2 varchar(50),
column3 int(3)
);
INSERT INTO table1
VALUES ("column1 value1", "column2 value1", 120),
("column1 value1", "column2 value1", 240),
("column1 value2", "column2 value1", 240),
("column1 value2", "column2 value2", 10);
Nesta mesa. Eu executo esta consulta SQL:
SELECT column1, column2, SUM(column3) FROM table1 GROUP BY column1, column2
É possível buscar o resultado em uma matriz associativa multidimensional com column1a chave de "nível 1" e column2& column3como um par de valor-chave?
Resultado desejado:
Array
(
[column1 value] => Array
(
[column2 value] => column3 value
)
)
Tentei usar PDO::FETCH_GROUP|PDO::FETCH_UNIQUE|PDO::FETCH_ASSOCcomo o argumento de estilo de busca, mas resultou em:
Array
(
[column1 value] => Array
(
[column2 key] => column2 value
[column3 key] => column3 value
)
)
É assim que estou executando minha consulta e buscando o resultado:
$stmt = $pdo->prepare("SELECT column1, column2, SUM(column3) FROM table GROUP BY column1, column2");
$stmt->execute(); $result = $stmt->fetchAll(PDO::FETCH_GROUP|PDO::FETCH_UNIQUE|PDO::FETCH_ASSOC);
Existe uma combinação de estilo de busca que me dará o resultado desejado ou terei que fazer isso programaticamente?
Respostas
Basicamente, você está preso fazendo isso programaticamente, mas pode fazer isso com uma função na fetchAllchamada; usando FETCH_GROUPpara fazer o agrupamento pela primeira coluna e usando a função para retornar o array apropriado da segunda e terceira colunas.
$result = $stmt->fetchAll(PDO::FETCH_GROUP|PDO::FETCH_FUNC,
function ($col2, $col3) {
return array($col2 => $col3);
});
Observe que isso retorna uma matriz com um nível extra:
Array
(
[column1 value1] => Array
(
[0] => Array
(
[column2 value1] => 360
)
)
[column1 value2] => Array
(
[0] => Array
(
[column2 value1] => 240
)
[1] => Array
(
[column2 value2] => 10
)
)
)
Você pode remover o nível extra por meio de uma combinação de array_mape array_reduce:
$result = array_map(function ($arr) {
return array_reduce($arr, function ($c, $a) { $c[key($a)] = reset($a);
return $c; }, []); }, $result);
Resultado:
Array
(
[column1 value1] => Array
(
[column2 value1] => 360
)
[column1 value2] => Array
(
[column2 value1] => 240
[column2 value2] => 10
)
)
No entanto, é provavelmente mais simples apenas percorrer a matriz:
$result = $stmt->fetchAll(PDO::FETCH_NUM);
$out = array(); foreach ($result as $array) { $out[$array[0]][$array[1]] = $array[2];
}
Aparentemente, a parte mais difícil nos modos de busca PDO é diferenciar o agrupamento da indexação . Todas as perguntas relacionadas a esses modos por algum motivo os confundem.
Pela natureza da sua consulta, eu diria que você precisa do agrupamento. Mas em sua combinação de modo de busca cabeludo, você está usando FETCH_UNIQUE, o que resulta na indexação, não no agrupamento.
É uma coisa boa que você forneceu algum MCVE - apenas alguns tiveram sucesso com a tag PDO, mas é uma coisa muito ruim que você não forneceu o resultado real desejado, mas apenas um esboço. Então, eu só posso imaginar que deve ser algo assim
{
"column1 value1": {
"column2 value1": "360"
},
"column1 value2": {
"column2 value1": "240",
"column2 value2": "10"
}
}
mas sua abordagem atual está dando a você este array com uma linha a menos .
Não conheço nenhuma combinação de modos de busca que possa dar o resultado desejado, mas a velha e boa busca manual sempre pode
$sql = "SELECT column1, column2, SUM(column3) sum FROM table1 GROUP BY column1, column2"; $stmt = $pdo->query($sql);
$data = []; foreach($stmt as $row) { $data[$row['column1']][$row['column2']] = $row['sum'];
}
No final, descobriu-se que seu MCVE não é tão bom. E será uma lição para você, criar sempre um exemplo sólido, funcional e não contraditório com o resultado certo desejado que possa ser comparado ao resultado real.
Infelizmente PDO::FETCH_GROUP, os resultados serão agrupados apenas pela primeira coluna obtida, então você não poderá agrupar por 2 colunas.
Mas você pode traduzir seu resultado para o resultado que deseja usando array_map, array_combineearray_column
$stmt = $pdo->prepare("SELECT column1, column2, SUM(column3) as column3 FROM table1 GROUP BY column1, column2");
$stmt->execute(); $result = $stmt->fetchAll(PDO::FETCH_GROUP|PDO::FETCH_ASSOC); $result = array_map(static function ($res) { return array_combine( array_column($res, 'column2'),
array_column($res, 'column3') ); }, $result);
var_dump($result);