Actualmente estoy usando este tipo de SQL en MySQL para insertar varias filas de valores en una sola consulta:
INSERT INTO `tbl` (`key1`,`key2`) VALUES ('r1v1','r1v2'),('r2v1','r2v2'),...
En las lecturas de PDO, las declaraciones de uso preparadas deberían darme una mejor seguridad que las consultas estáticas.
Por lo tanto, me gustaría saber si es posible generar "insertar múltiples filas de valores mediante el uso de una consulta" utilizando declaraciones preparadas.
En caso afirmativo, ¿puedo saber cómo puedo implementarlo?
php
pdo
insert
prepared-statement
hoball
fuente
fuente
$stmt->execute($data);
php.net/manual/en/… Básicamente todos los parámetros se pasan validados como cadenas. Simplemente recorra los datos después de crear la consulta y escriba manualmentebindValue
obindParam
pase el tipo como tercer argumento.Respuestas:
Insertar valores múltiples con declaraciones preparadas de DOP
Insertar múltiples valores en una declaración de ejecución. ¿Por qué porque de acuerdo con esta página es más rápido que las inserciones regulares?
más valores de datos o probablemente tenga un bucle que complete los datos.
Con las inserciones preparadas, necesita saber los campos en los que está insertando y la cantidad de campos para crear el? marcadores de posición para vincular sus parámetros.
Así es básicamente cómo queremos que se vea la declaración de inserción.
Ahora, el código:
Aunque en mi prueba, solo hubo una diferencia de 1 segundo al usar insertos múltiples e insertos preparados regularmente con un solo valor.
fuente
placeholders()
una y otra vez. Llámelo una vez antes del ciclo consizeof($datafields)
y agregue la cadena de resultados al$question_marks[]
interior del ciclo.La misma respuesta que el Sr. Balagtas, un poco más claro ...
Las versiones recientes de MySQL y PHP DOP hacen de soporte de varias filas
INSERT
declaraciones.Descripción general de SQL
El SQL se verá más o menos así, suponiendo una tabla de 3 columnas que le gustaría
INSERT
tener.ON DUPLICATE KEY UPDATE
funciona como se espera incluso con un INSERT de varias filas; agregue esto:Descripción general de PHP
Su código PHP seguirá lo habitual
$pdo->prepare($qry)
$stmt->execute($params)
llamadas y PDO.$params
será una matriz unidimensional de todos los valores para pasar aINSERT
.En el ejemplo anterior, debe contener 9 elementos; PDO usará cada conjunto de 3 como una sola fila de valores. (Insertar 3 filas de 3 columnas cada una = matriz de 9 elementos).
Implementación
El siguiente código está escrito para mayor claridad, no eficiencia. Trabaja con PHP
array_*()
funciones de para obtener mejores formas de asignar o recorrer sus datos si lo desea. Si puede usar transacciones obviamente depende de su tipo de tabla MySQL.Asumiendo:
$tblName
- el nombre de cadena de la tabla para INSERTAR$colNames
- Matriz unidimensional de los nombres de columna de la tabla Estos nombres de columna deben ser identificadores de columna MySQL válidos; escapar de ellos con backticks (``) si no están$dataVals
- matriz multidimensional, donde cada elemento es una matriz 1-d de una fila de valores para INSERTARCódigo de muestra
fuente
$rowPlaces
ya no sea necesario:$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));
será mucho más rápido entoncesforeach ($dataVals as $row => $data) {}
Por lo que vale, he visto que muchos usuarios recomiendan iterar a través de las instrucciones INSERT en lugar de construir como una sola consulta de cadena como lo hizo la respuesta seleccionada. Decidí ejecutar una prueba simple con solo dos campos y una instrucción de inserción muy básica:
Si bien la consulta general en sí misma tomó milisegundos o menos, la última consulta (cadena única) fue consistentemente 8 veces más rápida o más. Si esto se construyó para decir que refleja una importación de miles de filas en muchas columnas más, la diferencia podría ser enorme.
fuente
bind_param
declaración en la segunda rutina de importación"?(?,?)
, ¿verdad?La respuesta aceptada de Herbert Balagtas funciona bien cuando la matriz $ data es pequeña. Con matrices $ data más grandes, la función array_merge se vuelve prohibitivamente lenta. Mi archivo de prueba para crear la matriz $ data tiene 28 cols y tiene aproximadamente 80,000 líneas. El guión final tardó 41 segundos en completarse.
El uso de array_push () para crear $ insert_values en lugar de array_merge () resultó en una velocidad 100X con un tiempo de ejecución de 0.41s .
La problemática array_merge ():
Para eliminar la necesidad de array_merge (), puede crear los siguientes dos arreglos en su lugar:
Estas matrices se pueden usar de la siguiente manera:
fuente
array_push($data, ...array_values($row))
lugar de$data = array_merge($data, array_values($row));
. Mucho mas rápido.array_push()
está disponible incluso en php 4.array_push()
, sino porque @Mark está usando el desempaquetado de argumentos. ¿Notaste la...array_values()
llamada allí?array_values()
está disponible en php 4. No estoy seguro si eso es lo que quiere decirargument unpacking
.Dos posibles enfoques:
O:
Si los datos de todas las filas están en una sola matriz, usaría la segunda solución.
fuente
$stmt->execute();
debería estar fuera del bucle foreach?Esa no es simplemente la forma en que usa las declaraciones preparadas.
Está perfectamente bien insertar una fila por consulta porque puede ejecutar una instrucción preparada varias veces con diferentes parámetros. De hecho, esa es una de las mayores ventajas, ya que le permite insertar una gran cantidad de filas de manera eficiente, segura y cómoda.
Por lo tanto, es posible implementar el esquema que propone, al menos para un número fijo de filas, pero está casi garantizado que esto no es realmente lo que desea.
fuente
Una respuesta más corta: aplanar la matriz de datos ordenados por columnas y luego
Al insertar alrededor de 1,000 registros, no desea tener que recorrer cada registro para insertarlos cuando todo lo que necesita es un recuento de los valores.
fuente
Aquí está mi enfoque simple.
fuente
On the readings on PDO, the use prepared statements should give me a better security than static queries.
$workouts_id
, que pueden tener$value
s con datos bastante inesperados. No puede garantizar que tal vez no ahora, pero en el futuro otro desarrollador haga que estos datos sean inseguros. Así que creo que es más correcto hacer la consulta preparada por PDO.Aquí hay una clase que escribí hacer múltiples inserciones con la opción de purga:
fuente
Así es como lo hice:
Primero defina los nombres de columna que usará, o déjelo en blanco y pdo asumirá que desea usar todas las columnas de la tabla, en cuyo caso deberá informar los valores de las filas en el orden exacto en que aparecen en la tabla .
Ahora, suponga que ya tiene una matriz bidimensional preparada. Iterarlo y construir una cadena con sus valores de fila, como tal:
Ahora, lo que acaba de hacer es verificar si $ filas ya estaba definido, y si no, crearlo y almacenar valores de fila y la sintaxis SQL necesaria para que sea una declaración válida. Tenga en cuenta que las cadenas deben ir entre comillas dobles y comillas simples, por lo que se reconocerán rápidamente como tales.
Todo lo que queda por hacer es preparar la declaración y ejecutarla como tal:
Probado con hasta 2000 filas hasta ahora, y el tiempo de ejecución es pésimo. Ejecutaré algunas pruebas más y volveré aquí en caso de que tenga algo más que aportar.
Saludos.
fuente
Como aún no se ha sugerido, estoy bastante seguro de que LOAD DATA INFILE sigue siendo la forma más rápida de cargar datos, ya que deshabilita la indexación, inserta todos los datos y luego vuelve a habilitar los índices, todo en una sola solicitud.
Guardar los datos como un csv debería ser bastante trivial teniendo en cuenta fputcsv. MyISAM es el más rápido, pero aún obtienes un gran rendimiento en InnoDB. Sin embargo, hay otras desventajas, por lo que seguiría esta ruta si está insertando muchos datos y no se molesta con menos de 100 filas.
fuente
Aunque una vieja pregunta, todas las contribuciones me ayudaron mucho, así que aquí está mi solución, que funciona dentro de mi propia
DbContext
clase. El$rows
parámetro es simplemente una matriz de matrices asociativas que representan filas o modelos:field name => insert value
.Si usa un patrón que usa modelos, esto encaja perfectamente cuando se pasan los datos del modelo como una matriz, digamos desde un
ToRowArray
método dentro de la clase de modelo.fuente
$tableName
está expuesto al usuario, lo que no es así, está en el DAL. ¿Puedes ampliar tus reclamos? No es útil solo decir cosas.$tableName
?Aquí hay otra solución (delgada) para este problema:
Al principio, necesita contar los datos de la matriz fuente (aquí: $ aData) con count (). Luego usa array_fill () y genera una nueva matriz con tantas entradas como la matriz fuente tiene, cada una con el valor "(?,?)" (El número de marcadores de posición depende de los campos que utilice; aquí: 2). Entonces la matriz generada necesita ser implosionada y como pegamento se usa una coma. Dentro del ciclo foreach, debe generar otro índice con respecto al número de marcadores de posición que utiliza (número de marcadores de posición * índice de matriz actual + 1). Debe agregar 1 al índice generado después de cada valor enlazado.
fuente
Puede insertar varias filas en una sola consulta con esta función:
$ row es una matriz de matrices de valores. En su caso, llamaría a la función con
Esto tiene la ventaja de que utiliza declaraciones preparadas , al insertar varias filas con una sola consulta. ¡Seguridad!
fuente
Aquí está mi solución: https://github.com/sasha-ch/Aura.Sql basado en la biblioteca auraphp / Aura.Sql.
Ejemplo de uso:
Los informes de errores son bienvenidos.
fuente
Mi ejemplo del mundo real para insertar todos los códigos postales alemanes en una tabla vacía (para agregar nombres de ciudades más adelante):
Como puede ver, es totalmente flexible. No necesita verificar la cantidad de columnas ni verificar en qué posición se encuentra su columna. Solo necesita configurar los datos de inserción:
Estoy orgulloso de algunos de los constructores de cadenas de consulta, ya que funcionan sin funciones de matriz pesadas como array_merge. Especialmente vsprintf () fue un buen hallazgo.
Finalmente, necesitaba agregar 2x while () para evitar exceder el límite de memoria. Esto depende de su límite de memoria, pero es una buena solución general para evitar problemas (y tener 10 consultas sigue siendo mucho mejor que 10.000).
fuente
prueba.php
Database.php
fuente
Tuve el mismo problema y así es como lo logro por mí mismo, e hice una función para mí (y puedes usarlo si eso te ayuda).
Ejemplo:
INSERTAR EN LOS VALORES de los países (país, ciudad) (Alemania, Berlín), (Francia, París);
Si insertMultipleData ($ tabla, $ multi_params) devuelve TRUE , sus datos se han insertado en su base de datos.
fuente
En base a mis experimentos, descubrí que la instrucción de inserción mysql con filas de valores múltiples en una sola transacción es la más rápida.
Sin embargo, si los datos son demasiado, la
max_allowed_packet
configuración de mysql podría restringir la inserción de la transacción individual con varias filas de valores. Por lo tanto, las siguientes funciones fallarán cuando haya datos mayores que elmax_allowed_packet
tamaño de mysql :singleTransactionInsertWithRollback
singleTransactionInsertWithPlaceholders
singleTransactionInsert
El más exitoso en el escenario de insertar grandes datos es el
transactionSpeed
método, pero consume más tiempo que los métodos mencionados anteriormente. Entonces, para manejar este problema, puede dividir sus datos en fragmentos más pequeños y llamar a la inserción de transacción única varias veces o renunciar a la velocidad de ejecución mediante eltransactionSpeed
método.Aquí está mi investigación
Los resultados para 100,000 entradas para una tabla que contiene solo dos columnas son los siguientes
fuente
Esto funciono para mi
fuente
¿Qué tal algo como esto?
La idea detrás de esto es recorrer los valores de su matriz, agregando "números de identificación" a cada bucle para los marcadores de posición de la declaración preparada y, al mismo tiempo, agrega los valores a su matriz para los parámetros de enlace. Si no le gusta usar el índice "clave" de la matriz, puede agregar $ i = 0 y $ i ++ dentro del bucle. En este ejemplo, cualquiera de los dos funciona, incluso si tiene matrices asociativas con claves con nombre, funcionaría siempre que las claves fueran únicas. Con un poco de trabajo también estaría bien para matrices anidadas.
** Tenga en cuenta que substr quita las variables $ sql último espacio y coma, si no tiene un espacio necesitaría cambiar esto a -1 en lugar de -2.
fuente
La mayoría de las soluciones dadas aquí para crear la consulta preparada son más complejas de lo que deben ser. Usando las funciones integradas de PHP, puede crear fácilmente la declaración SQL sin una sobrecarga significativa.
Dado
$records
, una matriz de registros donde cada registro es en sí mismo una matriz indexada (en forma defield => value
), la siguiente función insertará los registros en la tabla dada$table
, en una conexión PDO$connection
, usando solo una sola declaración preparada. Tenga en cuenta que esta es una solución PHP 5.6+ debido al uso de desempaquetado de argumentos en la llamada aarray_push
:fuente