В настоящее время я использую этот тип SQL на MySQL, чтобы вставить несколько строк значений в один запрос:
INSERT INTO `tbl` (`key1`,`key2`) VALUES ('r1v1','r1v2'),('r2v1','r2v2'),...
В чтениях по PDO операторы, подготовленные к использованию, должны обеспечить мне большую безопасность, чем статические запросы.
Поэтому я хотел бы знать, возможно ли сгенерировать «вставку нескольких строк значений с помощью одного запроса» с использованием подготовленных операторов.
Если да, могу ли я узнать, как я могу это реализовать?
php
pdo
insert
prepared-statement
hoball
источник
источник
$stmt->execute($data);
php.net/manual/en/… В основном все параметры передаются проверенными как строки. Просто переберите данные после построения запроса и вручнуюbindValue
илиbindParam
передав тип в качестве третьего аргумента.Ответы:
Вставка нескольких значений с подготовленными заявлениями PDO
Вставка нескольких значений в одном операторе выполнения. Почему, потому что согласно этой странице это быстрее, чем обычные вставки.
больше значений данных, или у вас, вероятно, есть цикл, который заполняет данные.
С подготовленными вставками вам нужно знать поля, в которые вы вставляете, и количество полей для создания? заполнители, чтобы связать ваши параметры.
Именно так мы хотим, чтобы оператор вставки выглядел так.
Теперь код:
Хотя в моем тесте разница была только в 1 секунду при использовании нескольких вставок и обычных подготовленных вставок с одним значением.
источник
placeholders()
снова и снова. Вызовите его один раз перед циклом сsizeof($datafields)
и добавьте строку результата$question_marks[]
внутрь цикла.Тот же ответ, что и у мистера Балагтаса, чуть яснее ...
Последние версии MySQL и PHP PDO сделать поддержка нескольких строк
INSERT
заявления.Обзор SQL
SQL будет выглядеть примерно так, при условии, что вы хотите создать таблицу из 3 столбцов
INSERT
.ON DUPLICATE KEY UPDATE
работает как положено даже с многорядной INSERT; добавить это:Обзор PHP
Ваш PHP-код будет следовать обычным вызовам
$pdo->prepare($qry)
и$stmt->execute($params)
вызовам PDO.$params
будет одномерным массивом всех значений, передаваемых вINSERT
.В приведенном выше примере он должен содержать 9 элементов; PDO будет использовать каждый набор из 3 как один ряд значений. (Вставка 3 строк по 3 столбца в каждом = 9 элементов массива.)
Реализация
Ниже код написан для ясности, а не эффективности. Работайте с
array_*()
функциями PHP, чтобы лучше отображать или просматривать ваши данные, если хотите. Можно ли использовать транзакции, очевидно, зависит от типа таблицы MySQL.Предполагая, что:
$tblName
- имя строки таблицы для вставки$colNames
- одномерный массив имен столбцов таблицы. Эти имена столбцов должны быть действительными идентификаторами столбцов MySQL; избегайте их с помощью галочек (``), если они не$dataVals
- многомерный массив, где каждый элемент представляет собой 1-й массив строки значений для INSERTОбразец кода
источник
$rowPlaces
больше не нужно:$allPlaces = implode(',', array_fill(0, count($dataVals), '('.str_pad('', (count($colNames)*2)-1, '?,').')'));
votes
ADD UNIQUEunique_index
(user
,email
,address
);array_push($dataToInsert, ...array_values($dataVals));
будет намного быстрее, чемforeach ($dataVals as $row => $data) {}
Что бы это ни стоило, я видел, что многие пользователи рекомендуют выполнять итерации по операторам INSERT, а не строить их как однострочный запрос, как это сделал выбранный ответ. Я решил запустить простой тест с двумя полями и очень простым оператором вставки:
В то время как сам запрос занимал миллисекунды или меньше, последний (однострочный) запрос был последовательно в 8 раз быстрее или больше. Если бы это было сделано, чтобы отразить импорт тысяч строк во многих других столбцах, разница могла бы быть огромной.
источник
bind_param
во второй процедуре импорта нет операторов"?(?,?)
, верно?Принятый ответ Герберта Балагтаса хорошо работает, когда массив $ data мал. При больших массивах $ data функция array_merge становится слишком медленной. Мой тестовый файл для создания массива $ data имеет 28 столбцов и около 80 000 строк. Окончательный сценарий занял 41 с.
Использование array_push () для создания $ insert_values вместо array_merge () привело к ускорению в 100 раз со временем выполнения 0,41 с .
Проблемный array_merge ():
Чтобы устранить необходимость в array_merge (), вместо этого вы можете создать следующие два массива:
Эти массивы могут затем использоваться следующим образом:
источник
array_push($data, ...array_values($row))
вместо$data = array_merge($data, array_values($row));
. Намного быстрее.array_push()
доступна даже в php 4.array_push()
, а потому что @Mark использует распаковку аргументов. Заметили...array_values()
звонок там?array_values()
также доступен в php 4. Не уверен, что под этим вы подразумеваетеargument unpacking
.Два возможных подхода:
Или:
Если данные для всех строк находятся в одном массиве, я бы использовал второе решение.
источник
$stmt->execute();
быть вне цикла foreach?Это просто не то, как вы используете готовые заявления.
Вполне нормально вставлять одну строку в запрос, потому что вы можете выполнить один подготовленный оператор несколько раз с разными параметрами. Фактически, это одно из величайших преимуществ, поскольку оно позволяет вам эффективно и безопасно вставлять большое количество строк.
Поэтому, возможно, можно реализовать предложенную вами схему, по крайней мере, для фиксированного числа строк, но почти гарантировано, что это не совсем то, что вы хотите.
источник
Более короткий ответ: сгладьте массив данных, упорядоченный по столбцам, затем
При вставке 1000 записей или около того вам не нужно циклически просматривать каждую запись, чтобы вставить их, когда все, что вам нужно, - это подсчет значений.
источник
Вот мой простой подход.
источник
On the readings on PDO, the use prepared statements should give me a better security than static queries.
$workouts_id
, которое может иметь$value
s с довольно неожиданными данными. Вы не можете гарантировать, что, возможно, не сейчас, но в будущем другой разработчик сделает эти данные незащищенными. Поэтому я думаю, что более правильно сделать запрос, подготовленный PDO.Вот класс, который я написал, чтобы сделать несколько вставок с опцией очистки:
источник
Вот как я это сделал:
Сначала определите имена столбцов, которые вы будете использовать, или оставьте это поле пустым, и pdo предположит, что вы хотите использовать все столбцы таблицы - в этом случае вам нужно будет сообщить значения строк в точном порядке, в котором они отображаются в таблице. ,
Теперь предположим, что у вас уже есть двухмерный массив. Итерируйте его и создайте строку с вашими значениями строки, как таковые:
Теперь, что вы только что сделали, это проверили, определено ли уже $ row, и, если нет, создайте его и сохраните значения строк и необходимый синтаксис SQL, чтобы он был действительным оператором. Обратите внимание, что строки должны заключаться в двойные и одинарные кавычки, поэтому они будут быстро распознаваться как таковые.
Все, что осталось сделать, это подготовить оператор и выполнить так:
До сих пор тестировалось до 2000 строк, и время выполнения мрачное. Проведу еще несколько тестов и вернусь сюда, если у меня будет что-то еще.
С уважением.
источник
Поскольку это еще не было предложено, я уверен, что LOAD DATA INFILE по-прежнему является самым быстрым способом загрузки данных, поскольку он отключает индексирование, вставляет все данные и затем повторно включает индексы - все в одном запросе.
Сохранение данных в формате csv должно быть довольно тривиальным, учитывая fputcsv. MyISAM работает быстрее, но вы все равно получаете большую производительность в InnoDB. Есть и другие недостатки, поэтому я бы пошел по этому пути, если вы вставляете много данных, и не беспокоитесь о менее чем 100 строках.
источник
Хотя старый вопрос, все вклады мне очень помогли, вот мое решение, которое работает в моем
DbContext
классе.$rows
Параметр просто массив ассоциативных массивов , представляющих строку или модель:field name => insert value
.Если вы используете шаблон, который использует модели, он хорошо вписывается, когда данные модели передаются в виде массива, скажем, из
ToRowArray
метода в классе модели.источник
$tableName
, что он открыт для пользователя, а это не так, он в DAL. Можете ли вы расширить свои претензии? Бесполезно просто говорить вещи.$tableName
?Вот еще одно (тонкое) решение этой проблемы:
Сначала вам нужно посчитать данные исходного массива (здесь: $ aData) с помощью count (). Затем вы используете array_fill () и генерируете новый массив с таким количеством записей, как у исходного массива, каждый со значением «(?,?)» (Количество заполнителей зависит от используемых вами полей; здесь: 2). Затем сгенерированный массив нужно развернуть и в качестве клея использовать запятую. В цикле foreach вам нужно сгенерировать еще один индекс относительно количества используемых заполнителей (количество заполнителей * текущий индекс массива + 1). Вам нужно добавить 1 к сгенерированному индексу после каждого связанного значения.
источник
Вы можете вставить несколько строк в один запрос с помощью этой функции:
$ row это массив массивов значений. В вашем случае вы бы вызвали функцию с
Преимущество заключается в том, что вы используете подготовленные операторы , вставляя несколько строк одним запросом. Безопасность!
источник
Вот мое решение: https://github.com/sasha-ch/Aura.Sql на основе библиотеки auraphp / Aura.Sql.
Пример использования:
Сообщения об ошибках приветствуются.
источник
Мой пример из реального мира, чтобы вставить все немецкие почтовые индексы в пустую таблицу (чтобы добавить названия городов позже):
Как вы можете видеть его полностью гибким. Вам не нужно проверять количество столбцов или проверять, в какой позиции находится ваш столбец. Вам нужно только установить данные вставки:
Я горжусь некоторыми конструкторами строк запроса, поскольку они работают без тяжелых функций массива, таких как array_merge. Особенно vsprintf () была хорошей находкой.
Наконец, мне нужно было добавить 2x while (), чтобы избежать превышения лимита памяти. Это зависит от вашего лимита памяти, но в целом это хорошее общее решение, позволяющее избежать проблем (а наличие 10 запросов по-прежнему намного лучше, чем 10.000).
источник
test.php
database.php
источник
У меня была та же проблема, и вот как я выполняю для себя, и я сделал для себя функцию для нее (и вы можете использовать ее, если это поможет вам).
Пример:
INSERT INTO страны (страна, город) ЦЕННОСТИ (Германия, Берлин), (Франция, Париж);
Если insertMultipleData ($ table, $ multi_params) возвращает TRUE , ваши данные были вставлены в вашу базу данных.
источник
Основываясь на своих экспериментах, я обнаружил, что оператор вставки mysql с несколькими строками значений в одной транзакции является самым быстрым.
Однако, если данных слишком много, тогда
max_allowed_packet
настройка mysql может ограничить вставку одной транзакции несколькими строками значений. Следовательно, следующие функции потерпят неудачу, когда есть данные, превышающиеmax_allowed_packet
размер mysql :singleTransactionInsertWithRollback
singleTransactionInsertWithPlaceholders
singleTransactionInsert
Наиболее успешным в сценарии вставки огромных данных является
transactionSpeed
метод, но он требует больше времени, чем вышеупомянутые методы. Таким образом, для решения этой проблемы вы можете либо разбить ваши данные на более мелкие порции и вызвать одну транзакцию вставки несколько раз, либо отказаться от скорости выполнения с помощьюtransactionSpeed
метода.Вот мое исследование
Результаты для 100 000 записей для таблицы, содержащей только два столбца, приведены ниже
источник
Это сработало для меня
источник
что-то вроде этого:
Идея заключается в том, чтобы циклически проходить через значения вашего массива, добавляя «номера идентификаторов» в каждый цикл для заполнителей заполненных вами операторов, в то же время вы добавляете значения в свой массив для параметров привязки. Если вам не нравится использовать индекс «key» из массива, вы можете добавить $ i = 0 и $ i ++ внутри цикла. В этом примере любой из них работает, даже если у вас есть ассоциативные массивы с именованными ключами, он все равно будет работать, если ключи будут уникальными. С небольшой работой это было бы хорошо и для вложенных массивов ..
** Обратите внимание, что substr удаляет переменные $ sql с последним пробелом и запятой, если у вас нет пробела, вам нужно изменить это значение на -1, а не на -2.
источник
Большинство решений, приведенных здесь для создания подготовленного запроса, являются более сложными, чем они должны быть. Используя встроенные функции PHP, вы можете легко создавать оператор SQL без значительных накладных расходов.
Для данного
$records
массива записей, где каждая запись сама является индексированным массивом (в формеfield => value
), следующая функция вставит записи в данную таблицу$table
при подключении к PDO$connection
, используя только один подготовленный оператор. Обратите внимание, что это решение PHP 5.6+ из-за использования распаковки аргументов при вызовеarray_push
:источник