2009-09-07 21 views
19

Estoy usando PDOStatement para consultar la base de datos. Cada vez que obtengo una fila devuelta, quiero que se busque en una matriz, con el $row[0] como clave, y los elementos subsiguientes en la fila como valores.PHP PDOStatement: Fetch A Row, como la primera columna como la clave de una matriz

puedo, por supuesto, escribir una combinación de foreach bucles y condicionales if para hacer el trabajo, tales como el siguiente:

private static function GetMySQLResult($dbname, $sqlString) { 


     $dbh = self::ConstructPDOObject($dbname); 
     $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); 

     $result=array(); 
     foreach ($dbh->query($sqlString) as $row) 
     { 
      $result[$row[0]][]=$row[1]; // the simplest case for 2 columns, should add more to handle more columns 

     } 

     return $result; 

} 

pero estoy en busca de un método existente; ¿Existe un método que ya exista?

+0

Su código en realidad agrupa filas en una clave no única, ¿es eso también un requisito de una posible respuesta? –

Respuesta

2

Algunos consejos, debe pasar el estilo de búsqueda correcto al método PDOStatement->fetch() para que no termine con datos dobles (nombres de columnas numéricas y textuales). Como $ row [0] y $ row ['id'] que ambos contienen el mismo valor cuando usas PDO :: FETCH_BOTH.

$result = $dbh->query($sqlString); 
while ($row = $result->fetch(PDO::FETCH_NUM)) { 
... 

cuanto a su pregunta, usted tendrá que obtener todos los resultados y luego crear una matriz con los $ fila [ 'id'] como la clave y la fila de resultado como el valor - al igual que lo está haciendo . Construí una biblioteca ORM completa alrededor de PDO y nunca pude encontrar nada para hacer esto automáticamente.

$result = $dbh->query($sqlString); 

$results = array(); 
while ($row = $result->fetch(PDO::FETCH_NUM)) { 
    $results[$row[0]] = $row; 
} 

return $results; 
+0

¿En qué se diferencia esto de usar un bucle foreach, que es lo que intentamos evitar? –

22

Créditos a devdRew. Check the other question here.

Aparentemente, puede como se indica en la respuesta. Lo revisé también y funciona muy bien.

$q = $db->query("SELECT `name` AS name, `value` AS value FROM `settings`;"); 
$r = $q->fetchAll(PDO::FETCH_KEY_PAIR); 

EDITAR

Esta respuesta requiere que especifique un máximo de 2 columnas: 1 llave y 1 valor. Si necesita recuperar más claves de la base de datos, verifique la respuesta a continuación y lea el comentario de @nullabilty. Para aquellos que son perezosos, aquí es su método:

$q->fetchAll(PDO::FETCH_GROUP|PDO::FETCH_UNIQUE|PDO::FETCH_ASSOC); 
+0

Este es el único método que utilizará la primera columna como clave, en caso de que necesite columnas adicionales, CONCAT o campos adicionales similares como cadena delimitada para el valor de la segunda columna y use 'explotar' para tener una matriz antes de usar el valor. –

+0

@ nickl- usar 'CONCAT' para este propósito es una idea horrible; esta respuesta debe usarse exclusivamente para pares clave-valor, algo para lo que fue diseñado. –

+0

¿Estás dejando que la recompensa expire? –

1

Además del escenario tabla de dos columnas, no hay nada en el nivel de DOP para manejar esto, pero se podría escribir un iterador reutilizable para que, de esta manera:

class FirstColumnKeyIterator implements Iterator 
{ 
    private $stmt; 
    private $key; 
    private $data; 
    private $mode; 

    public function __construct(PDOStatement $stmt, $fetch_mode = PDO::FETCH_NUM) 
    { 
     $this->stmt = $stmt; 
     $this->mode = $fetch_mode; 
     $this->fetch(); 
    } 

    private function fetch() 
    { 
     if (false !== ($this->data = $this->stmt->fetch($this->mode))) { 
      $this->key = current(array_splice($this->data, 0, 1)); 
     } 
    } 

    public function rewind() 
    { 
     // nil operation 
    } 

    public function key() 
    { 
     return $this->key; 
    } 

    public function current() 
    { 
     return $this->data; 
    } 

    public function next() 
    { 
     $this->fetch(); 
    } 

    public function valid() 
    { 
     return false !== $this->data; 
    } 
} 

El constructor toma un PDOStatement y un modo opcional fetch (columnas numéricas de forma predeterminada, pero se puede cambiar a PDO::FETCH_ASSOC de una matriz asociativa) y permite recorrer los resultados de la consulta utilizando un típico foreach.

Ejemplo de uso:

$dbh = new PDO(/* etc */); 

$stmt = $dbh->query('SELECT * FROM accounts'); 
foreach (new FirstColumnKeyIterator($stmt, PDO::FETCH_ASSOC) as $key => $value) { 
     echo $key, ' = ', print_r($value, true), PHP_EOL; 
} 
+0

10 puntos por creatividad =) pero encontrarás de esta manera más costosa que la escenario original. Puede mejorar esto al hacer referencia al 'nuevo iterador' primero y siempre evitar' como $ clave => # valor' si puede evitarlo. Descubrirá que un bucle for en una referencia 'array_keys' arrojará mejores resultados siempre que también se haga referencia al conteo. 'for ($ i = 0; $ i

+0

@nickl iterators son siempre más caros que una matriz "simple" porque el código adicional se ejecuta en cada ciclo que no desaparecerá al hacer referencia a la instancia; eliminar el 'clave => valor' tampoco es una opción, ya que de lo contrario no hay forma de obtener la clave :) –

+0

formas alternativas de usar un iterador y aún obtener la clave podría ser con do..while o mientras tanto y Puedo pensar en varios bucles, es decir. 'for ($ it = new ArrayIterator ($ data); $ it-> valid(); $ it-> next()) echo $ it-> key(). ' => '. $ it-> current(); 'pero estoy seguro de que pensaste en esto también.=) –

3

Que yo sepa, no hay método existente que hacerlo en PHP, pero hay un par de maneras en que podría lograr lo que quiere.

Uno de los primeros que se lo dijo Xeoncross pero un poco modificada:

$pdostmt = $pdo->query("SELECT ... FROM your_table"); 

$res = array(); 

foreach ($pdostmt->fetchAll(PDO::FETCH_ASSOC) as $row) 
{ 
    $res[array_shift($row)] = $row; 
} 

De lo contrario, puede crear una clase con un método __set() para atrapar la asignación de variables:

class at_res 
{ 
    public $key; 
    public $values = array(); 
    protected $flag = true; 

    public function __set($var, $value) 
    { 
    if ($this->flag) 
    { 
     $this->key = $value; 
     $this->flag = false; 
    } 
    else 
    { 
     $this->values[$var] = $value; 
    } 
    } 

    public function extract() 
    { 
    return array($this->key => $this->values); 
    } 
} 


$pdo = new PDO(...); 

$pdostmt = $pdo->query("SELECT ... FROM your_table"); 

$res = $pdostmt->fetchObject('at_res'); 

var_dump($res->extract()); 

creo que sirve .

13
$stmt->fetchAll(PDO::FETCH_GROUP|PDO::FETCH_UNIQUE); 

aunque un poco de un truco, pero realmente la única manera de hacer esto ya que alguien decided FETCH_KEY_PAIR deberán exigir sólo el 2 columna de resultados del conjunto.

Nota: la primera columna se utiliza una clave y no se devuelve en el conjunto de resultados de ninguna otra forma.

+13

Gracias, extendí el mío a 'PDO :: FETCH_GROUP | PDO :: FETCH_UNIQUE | PDO :: FETCH_ASSOC' para obtener exactamente lo que necesito. – nullability

+0

nice addition there thx – Louis

+0

Nota: la primera columna se utiliza una clave y no se devuelve en el conjunto de resultados de ninguna otra forma. Aún puede duplicar su primera columna usando "SELECT firstcolumn AS id, firstcolumn, secondcolumn ..." si desea obtener la columna es results –

Cuestiones relacionadas