2009-09-07 12 views
19

Sto usando PDOStatement per interrogare il database. Ogni volta che ottengo una riga restituita, voglio che venga recuperata in un array, con il $row[0] come chiave e gli elementi successivi nella riga come valori.PDOStatement PHP: Recupera una riga, come prima colonna come chiave di una matrice

posso, ovviamente, scrivere una combinazione di foreach loop e if condizionali per fare il lavoro, come ad esempio il seguito:

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; 

} 

ma sto cercando un metodo esistente; c'è un tale metodo già esiste?

+0

Il tuo codice raggruppa effettivamente le righe su una chiave non univoca, è anche questo un requisito di una possibile risposta? –

risposta

2

Alcuni suggerimenti, è necessario passare lo stile di recupero corretto al metodo PDOStatement->fetch() in modo da non finire con i doppi dati (nomi di colonna numerici e testuali). Come $ row [0] e $ row ['id'] che contengono entrambi lo stesso valore quando usi PDO :: FETCH_BOTH.

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

Per quanto riguarda la tua domanda, si dovrà prendere tutti i risultati e quindi creare un array con il $ row [ 'id'] come la chiave e la riga del risultato come valore - proprio come si sta facendo . Ho costruito un'intera libreria ORM attorno a PDO e non ho mai trovato nulla per farlo automaticamente.

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

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

return $results; 
+0

In che modo è diverso usare un ciclo foreach, che cosa stiamo cercando di evitare? –

22

I crediti vanno a devdRew. Check the other question here.

Apparentemente, come indicato nella risposta. Ho controllato pure e funziona benissimo.

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

EDIT

Questa risposta richiede di specificare un massimo di 2 colonne: 1 chiave e il valore 1. Se è necessario recuperare più chiavi dal database, controllare la risposta sotto e leggere il commento di @nullabilty. Per coloro che sono pigri, ecco il suo metodo:

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

Questo è l'unico metodo che utilizzerà la prima colonna come chiave, nel caso in cui si richiedano colonne aggiuntive, CONCAT o simili i campi aggiuntivi come stringa delimitata per il valore della 2a colonna e si usi 'explode' per avere una matrice prima di utilizzare il valore. –

+0

@ nickl- usare 'CONCAT' per questo scopo è un'idea orribile; questa risposta dovrebbe essere usata esclusivamente per coppie chiave-valore, qualcosa per cui è stato progettato. –

+0

Stai lasciando scadere il premio? –

1

Oltre allo scenario tabella a due colonne, non c'è nulla a livello DOP per gestire questo, ma si potrebbe scrivere un iteratore riutilizzabile per esso, come questo:

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

Il costruttore prende un PDOStatement e modalità opzionale fetch (colonne numeriche per impostazione predefinita, ma può essere modificato in PDO::FETCH_ASSOC per un array associativo) e consente di iterare i risultati dell'interrogazione utilizzando un tipico foreach.

Esempio di utilizzo:

$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 punti per creatività =) ma troverai questo modo più costoso del scenario originale. Puoi migliorare questo facendo prima riferimento a 'new Iterator' e sempre evitando' as $ key => # value' se puoi aiutarlo. Scoprirai che un ciclo for su un 'array_keys referenziato 'produrrà risultati migliori se si fa riferimento anche al conteggio. 'for ($ i = 0; $ i

+0

Gli iteratori @nickl sono sempre più costosi di una matrice "semplice" perché il codice extra viene eseguito ad ogni ciclo che non andrà via facendo riferimento all'istanza; anche rimuovere 'key => value' non è un'opzione, dato che non c'è modo di ottenere la chiave altrimenti :) –

+0

modi alternativi per usare un iteratore e ottenere comunque la chiave potrebbe essere con do..while o mentre per quella materia e Posso pensare a diversi loop per esempio. 'for ($ it = new ArrayIterator ($ data); $ it-> valid(); $ it-> next()) echo $ it-> key(). ' => '. $ it-> current(); 'ma sono sicuro che hai pensato anche a questi.=) –

3

AFAIK, non ci sono nessun metodo esistente che l'avrebbe fatto in PHP, ma ci sono un paio di modi si può ottenere quello che vuoi.

Uno dei primi di essere ciò che Xeoncross detto, ma un po 'modificata:

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

$res = array(); 

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

In caso contrario, è possibile creare una classe con un metodo __set() per la cattura di assegnazione variabile:

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

Speranza che aiuta .

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

anche se un po 'di hack, ma davvero l'unico modo per fare questo dato che qualcuno decided FETCH_KEY_PAIR dovrebbe richiedere solo 2 colonna risultato del set.

Nota: la prima colonna viene utilizzata una chiave e non viene restituita nel set di risultati in nessun altro modulo.

+13

Grazie, ho esteso il mio a 'PDO :: FETCH_GROUP | PDO :: FETCH_UNIQUE | PDO :: FETCH_ASSOC' per ottenere esattamente ciò di cui ho bisogno. – nullability

+0

bella aggiunta ci thxx – Louis

+0

Nota: prima colonna viene utilizzata una chiave e non viene restituita nel set di risultati in qualsiasi altra forma. È ancora possibile duplicare la prima colonna utilizzando "SELEZIONA id firstcolumn AS, firstcolumn, secondcolumn ..." se si desidera ottenere la colonna come risultati –

Problemi correlati