22 Stimmen

Wie kann ich mit Zend_Db mehr als eine Zeile hinzufügen?

Ich habe ein Array mit Informationen, die mehr oder weniger wie folgt aussehen:

$data[] = array('content'=>'asd');
$data[] = array('content'=>'asdf');

Und ich möchte beide Einträge in die Datenbank aufnehmen.

$db->insert('table', $data);

fügt nicht beide Einträge hinzu. Was mache ich falsch? Muß ich Zend_ Db_Table verwenden?

$data = array('content'=>'asdf');
$db->insert('table', $data);

funktioniert natürlich

33voto

markus Punkte 39397

Ich glaube nicht das Zend_Db das Einfügen von mehreren Zeilen unterstützt.

Wenn Sie aber nur zwei Reihen oder etwas mehr haben, können Sie einfach eine Schleife verwenden.

foreach ($data as $row)
{
    $db->insert('table', $row)
}

Bill Karwin , ein ehemaliger Zend Framework-Entwickler, schrieb dies vor einiger Zeit auf Nabble :

Rowsets sind im Grunde ein Sammlungsobjekt, also würde ich Methoden zu dieser Klasse hinzufügen, damit Zeilen zum Set hinzugefügt werden können. Sie sollten also in der Lage sein, dies zu tun:

// creates a rowset collection with zero rows
$rowset = $table->createRowset();

// creates one row with unset values 
$row = $table->createRow();

// adds one row to the rowset 
$rowset->addRow($row); 

// iterates over the set of rows, calling save() on each row
$rowset->save(); 

Es macht keinen Sinn, eine Ganzzahl an createRowset() zu übergeben, um N leere Zeilen zu erstellen. Man müsste sie ohnehin nur durchlaufen, um sie mit Werten zu füllen. Sie könnten also genauso gut eine Schleife schreiben, um einzelne Zeilen zu erstellen und mit Anwendungsdaten zu füllen, und sie dann der Sammlung hinzufügen.

$rowset = $table->createRowset();
foreach ($appData as $tuple) 
{
    $row = $table->createRow($tuple);
    $rowset->addRow($row);
}
$rowset->save();

Es ist sinnvoll, die Übergabe eines Arrays von Arrays an createRowset() zuzulassen, da dies mit der Verwendung der Übergabe eines Tupels an createRow() übereinstimmen würde.

$rowset = $table->createRowset($appData); // pass array of tuples

Dies würde die gleiche Schleife wie das vorherige Beispiel oben ausführen (mit Ausnahme des save() am Ende) und ein neues Rowset mit neuen Zeilen erstellen, die dann mit save() gespeichert werden können.

In SQL gibt es zwei Möglichkeiten, die Effizienz beim Einfügen von Daten zu verbessern:

  1. Verwenden Sie eine einzige INSERT-Anweisung mit mehreren Zeilen:

    INSERT INTO t (col1, col2, col3) VALUES (1, 2, 3), (4, 5, 6), (7, 8, 9);

  2. Bereiten Sie eine INSERT-Anweisung vor und führen Sie sie mehrfach aus:

    PREPARE INSERT INTO t (col1, col2, col3) VALUES (?, ?, ?); 1, 2, 3 AUSFÜHREN EXECUTE 4, 5, 6 EXECUTE 7, 8, 9

Die Unterstützung einer dieser Verbesserungen würde jedoch die Komplexität der Klassen Row und Rowset erhöhen. Das liegt an der internen Art und Weise wie die aktuelle Zend_Db_Table_Row Klasse zwischen einer Zeile unterscheidet die INSERTed oder UPDATEd sein muss wenn man save() aufruft. Diese Unterscheidung wird durch das Row Objekt gekapselt, so dass das Rowset nicht weiß ob die einzelnen Zeilen neue Zeilen oder modifizierte Kopien von bestehenden Zeilen sind. Damit die Rowset-Klasse eine mehrzeilige save()-Methode anbieten kann, die effizienteres SQL verwendet, müsste die Verwaltung von unsauberen Daten völlig umgestaltet werden. Die einfachere Lösung ist, dass das Rowset über seine Zeilen iteriert und save() für jede Zeile aufruft. Dies ist besser für die OO-Kapselung, hilft aber nicht bei der Optimierung von SQL für das Einfügen eines Rowsets.

In jedem Fall ist es sehr selten, dass bei einer typischen Webanfrage viele Datenzeilen geladen werden, wenn der Bedarf an effizientem SQL am größten ist. Der Unterschied in der Effizienz bei einer kleinen Anzahl von Zeilen ist gering, so dass eine spürbare Verbesserung nur dann eintritt, wenn eine große Anzahl von Zeilen geladen wird. Wenn das der Fall ist, sollten Sie INSERT ohnehin nicht verwenden, sondern die LOAD DATA-Anweisung von MySQL oder eine gleichwertige Funktion, wenn Sie ein anderes RDBMS verwenden. INSERT ist in der Regel nicht die effizienteste Wahl für das Laden großer Datenmengen.

Was die Rückgabe von automatisch generierten Schlüsseln angeht, würde ich mir nicht die Mühe machen. Beachten Sie, dass Sie bei der Verwendung von einfachem SQL (z. B. in der mysql CLI), wenn Sie mehrere Zeilen in eine einzige INSERT-Anweisung einfügen, nur den zuletzt generierten ID-Wert erhalten können, nicht die ID-Werte für alle eingefügten Zeilen. Das ist ein SQL-Verhalten, das für jede Sprache und jedes Framework gilt.

INSERT INTO t (col1, col2, col3) VALUES (1, 2, 3), (4, 5, 6), (7, 8, 9);
SELECT LAST_INSERT_ID(); -- returns only the id for the third tuple

Wenn Sie die ID für jede Zeile benötigen, sollten Sie eine Schleife schreiben und die Zeilen nacheinander einfügen, wobei Sie die generierte ID nach jeder eingefügten Zeile abrufen.

19voto

Bill Karwin Punkte 493880

Sie können jede beliebige SQL-Syntax ausführen - einschließlich mehrzeiliger INSERT Anweisungen -- über die Zend_Db_Adapter_Abstract::query() Methode.

Aber die Methoden der Zend_Db_Table y Zend_Db_Table_Rowset Klassen haben keine Unterstützung für das Einfügen mehrerer Zeilen in einem Durchgang.

13voto

risnandar Punkte 5373

Um mehrere Zeilen einzufügen kann man Zend_Db verwenden

$stmt = $table->getAdapter()->prepare('INSERT INTO tablename (col1, col2, col3) VALUES (?, ?, ?), (?, ?, ?)');

$stmt->execute( array($value1, $value2, $value3, $value4, $value5, $value6) );

(von Bill Karwin)

in Ihrem Fall können wir das in diesen Code ändern:

$data[] = array('content'=>'asd');
$data[] = array('content'=>'asdf');

$stmt = $table->getAdapter()->prepare('INSERT INTO table (col1) VALUES (?), (?)');
$stmt->execute( $data );

um diese '(?), (?)' dynamisch zu generieren, falls die Daten dynamisch sind, können Sie dieses Snippet verwenden:

$values = implode(',',array_fill(0,count($data),'(?)'));

Ich hoffe, das hilft

Grüße, Riki Risnandar

3voto

ovnia Punkte 2350

Hier ist meine Lösung:

public function saveRows($array) {
        $vAmount    = count($array);
        $values     = array();
        $columns    = array();

        foreach ($array as $colval) {
            foreach ($colval as $column=>$value) {
                array_push($values,$value);
                !in_array($column,$columns) ? array_push($columns,$column) : null;
            }
        }

        $cAmount    = count($columns);
        $values     = array_chunk($values, $cAmount);
        $iValues    = '';
        $iColumns   = implode("`, `", $columns);

        for($i=0; $i<$vAmount;$i++)
            $iValues.="('".implode("', '", $values[$i])."')".(($i+1)!=$vAmount ? ',' : null);

        $data="INSERT INTO `".$this->_name."` (`".$iColumns."`) VALUES ".$iValues;
        die($data);
        $this->query($data);
    }

1voto

Knase Punkte 1182

Es ist Arbeit.

 $query = 'INSERT INTO ' . $db->quoteIdentifier('table') . ' (`col1`, `col2`) VALUES ';
    $queryVals = array();
    foreach ($data as $row) {
        foreach($row as &$col) {
            $col = $db->quote($col);
        }
        $queryVals[] = '(' . implode(',', $row) . ')';
    }
    $stmt = $db->query($query . implode(',', $queryVals));

wie man mehrere Insert-Abfragen im Zend Framework erstellt

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X