Как мне добавить более одной строки с Zend_Db?

У меня есть массив с информацией, которая выглядит примерно так:

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

И я хочу добавить обе записи в базу данных.

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

не добавляет обе записи. Что я делаю неправильно? Обязательно ли использовать Zend_ Db_Table?

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

конечно работает


person Thomaschaaf    schedule 03.05.2009    source источник
comment
Запрос функции множественной вставки в Zend 2.0 (ZF2-475) был закрыто как wontfix.   -  person Tgr    schedule 18.12.2012


Ответы (6)


Я не думаю, что Zend_Db поддерживает вставку нескольких строк.

Но если у вас всего две строки или немного больше, вы можете просто использовать цикл.

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


Билл Карвин, бывший разработчик Zend Framework, написал это некоторое время назад на Nabble:

Наборы строк в основном представляют собой объект коллекции, поэтому я бы добавил в этот класс методы, позволяющие добавлять строки в набор. Итак, вы должны уметь это делать:

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

Нет смысла передавать целое число в createRowset () для создания N пустых строк. Вам просто нужно будет перебирать их, чтобы в любом случае заполнить их значениями. Таким образом, вы также можете написать цикл для создания и заполнения отдельных строк данными приложения, а затем добавить их в коллекцию.

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

Имеет смысл разрешить передачу массива массивов в createRowset (), поскольку это согласовывалось бы с использованием передачи кортежа в createRow ().

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

Это будет выполнять тот же цикл, что и в предыдущем примере выше (за исключением save () в конце), создавая новый набор новых строк, готовый к save () d.

В SQL есть два способа повысить эффективность вставки данных:

  1. Используйте один оператор INSERT с несколькими строками:

    ВСТАВИТЬ В t (col1, col2, col3) ЗНАЧЕНИЯ (1, 2, 3), (4, 5, 6), (7, 8, 9);

  2. Подготовьте оператор INSERT и выполните его несколько раз:

    ПОДГОТОВИТЬ ВСТАВИТЬ В t (col1, col2, col3) VALUES (?,?,?); ВЫПОЛНИТЬ 1, 2, 3 ВЫПОЛНИТЬ 4, 5, 6 ВЫПОЛНИТЬ 7, 8, 9

Однако поддержка любого из этих улучшений усложнила бы классы Row и Rowset. Это связано с внутренним способом, которым текущий класс Zend_Db_Table_Row различает строку, которую нужно вставить или обновить, когда вы вызываете save (). Это различие инкапсулировано объектом Row, поэтому Rowset не знает, являются ли отдельные строки новыми строками или измененными копиями существующих строк. Поэтому, чтобы класс Rowset предлагал многострочный метод save (), который использует более эффективный SQL, необходимо полностью реорганизовать управление грязными данными. Более простое решение состоит в том, чтобы набор строк перебирал свои строки, вызывая save () для каждой из них. Это лучше для инкапсуляции объектно-ориентированного программирования, хотя не помогает оптимизировать SQL для вставки набора строк.

В любом случае очень редко массовая загрузка большого количества строк данных в типичном веб-запросе, когда существует наибольшая потребность в эффективном SQL. Разница в эффективности для небольшого количества строк невелика, поэтому это будет заметным улучшением только в том случае, если вы загружаете огромное количество строк массово. В этом случае вам все равно не следует использовать INSERT, вы должны использовать оператор MySQL LOAD DATA или аналогичную функцию, если вы используете другой бренд RDBMS. INSERT обычно не самый эффективный вариант для загрузки большого количества данных.

Что касается возврата автоматически сгенерированных ключей, я бы не стал беспокоиться. Обратите внимание, что если вы используете простой SQL (например, в mysql CLI) и вставляете несколько строк в один оператор INSERT, вы можете получить только последнее сгенерированное значение идентификатора, а не значения идентификатора для всех вставленных строк. Это поведение SQL; это верно для любого языка или любой структуры.

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

Если вам нужен идентификатор для каждой строки, вы должны написать цикл и вставлять строки по одной, получая сгенерированный идентификатор после каждой вставленной строки.

person markus    schedule 03.05.2009
comment
Это неверно: $ sql = INSERT INTO beautiful (name, age) VALUES ('Helen', 24), ('Katrina', 21); работает (просто пример) - person Thomaschaaf; 03.05.2009
comment
ты прав. Я до сих пор не думаю, что zf поддерживает это, и нигде в руководстве нет намека на это. но я не уверен. - person markus; 03.05.2009

Вы можете выполнить любой синтаксис SQL, в том числе многострочные операторы INSERT, с помощью метода Zend_Db_Adapter_Abstract::query().

Но методы классов Zend_Db_Table и Zend_Db_Table_Rowset не поддерживают вставку нескольких строк за один раз.

person Bill Karwin    schedule 03.05.2009
comment
@Elzo Valugi, никакого insertMultiple() метода в мануале и во фреймворке нет - person Green; 29.08.2012
comment
есть настоящее, воля (возможное / вероятное) будущее. может мне стоит использовать бы. Просто для ясности :) - person Elzo Valugi; 29.08.2012

для вставки нескольких строк вы можете использовать Zend_Db

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

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

(от Билла Карвина)

в вашем случае мы можем изменить это на этот код:

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

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

для динамической генерации этих '(?), (?)', если данные являются динамическими, вы можете попробовать использовать этот фрагмент:

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

надеюсь это поможет

С уважением, Рики Риснандар

person risnandar    schedule 19.04.2011
comment
Я не думаю, что это работает? У меня есть $ list = array (); $ list [] = array (': x' = ›1, ': y' =› 1); $ stmt = $ this- ›table-› getAdapter () - ›prepare ('INSERT INTO here (x, y) VALUES (: x,: y), (: x,: y)'); $ stmt- ›execute ($ list); и он говорит: «Недопустимый номер параметра: количество связанных переменных не соответствует количеству токенов». Если я не использую массив MD, тогда все в порядке ... Я не думаю, что execute должен принимать массив MD? - person Intellix; 15.01.2012
comment
это не работает для меня, я получаю сообщение об ошибке, что слишком много заполнителей. Пытаюсь вставить 50 000 строк. - person Ray; 16.04.2014

вот мое решение:

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);
    }
person ovnia    schedule 10.08.2013
comment
Вам действительно следует избегать параметров запроса. - person Eric Seastrand; 08.03.2016
comment
Мне нужно вызвать execute () $this->query($data)->execute();, и он сработает - person Rafael Guimarães; 12.11.2019

Это работает.

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

как создать множественный запрос вставки в платформе zend

person Knase    schedule 05.03.2013

Если вы все же используете ZF2, решение может быть таким:

$insert = $this->getSql()->insert();
foreach ($values as $value) {
    $relation = array(
        'column_one' => $value,
        'column_two' => $value
    );
    $insert->values($relation, Insert::VALUES_MERGE);
}

$insertRes = $this->executeInsert($insert);
person Sergei Khaletskiy    schedule 25.02.2013
comment
Флаг Insert :: VALUES_MERGE, похоже, работает только для объединения пар столбцов / значений, которые будут вставлены как одна строка. Флаг по умолчанию (Insert :: VALUES_SET) полностью перезаписывает используемые пары столбец / значение, в то время как этот добавляет новые пары в конец предыдущих (перезаписывая любые существующие имена столбцов новыми значениями). - person ant7; 23.03.2021