¿Es posible insertar varias filas a la vez en una base de datos SQLite?


En MySQL puede insertar varias filas de esta manera:

INSERT INTO 'tablename' ('column1', 'column2') VALUES
    ('data1', 'data2'),
    ('data1', 'data2'),
    ('data1', 'data2'),
    ('data1', 'data2');

Sin embargo, estoy recibiendo un error cuando trato de hacer algo como esto. ¿Es posible insertar varias filas a la vez en una base de datos SQLite? ¿Cuál es la sintaxis para hacer eso?

Author: Andrew, 2009-10-23

24 answers

Actualizar

Como BrianCampbell señala aquí, SQLite 3.7.11 y superiores ahora soporta la sintaxis más simple del post original . Sin embargo, el enfoque que se muestra sigue siendo apropiado si desea la máxima compatibilidad entre las bases de datos heredadas.

Respuesta original

Si tuviera privilegios, me toparía con respuesta de andy: puede insertar varias filas en SQLite, solo necesita sintaxis diferente. Para que quede perfectamente claro, el Ejemplo de MySQL de OPs:

INSERT INTO 'tablename' ('column1', 'column2') VALUES
  ('data1', 'data2'),
  ('data1', 'data2'),
  ('data1', 'data2'),
  ('data1', 'data2');

Esto puede ser refundido en SQLite como:

     INSERT INTO 'tablename'
          SELECT 'data1' AS 'column1', 'data2' AS 'column2'
UNION ALL SELECT 'data1', 'data2'
UNION ALL SELECT 'data1', 'data2'
UNION ALL SELECT 'data1', 'data2'

Una nota sobre el rendimiento

Originalmente utilicé esta técnica para cargar eficientemente grandes conjuntos de datos desde Ruby on Rails. Sin embargo, como Jaime Cook señala, no está claro que esto sea un envoltorio individual INSERTs más rápido dentro de una sola transacción:

BEGIN TRANSACTION;
INSERT INTO 'tablename' table VALUES ('data1', 'data2');
INSERT INTO 'tablename' table VALUES ('data3', 'data4');
...
COMMIT;

Si la eficiencia es su objetivo, debe probar esto primero.

Una nota sobre UNIÓN vs UNIÓN TODOS

Como varios la gente comentó, si usas UNION ALL (como se muestra arriba), todas las filas se insertarán, por lo que en este caso, obtendrás cuatro filas de data1, data2. Si omite el ALL, entonces se eliminarán las filas duplicadas (y la operación presumiblemente será un poco más lenta). Estamos usando UNION ALL ya que coincide más con la semántica del post original.

Para concluir

P.d.: Por favor +1 la respuesta de andy , ¡no la mía! Él presentó la solución primero.

 559
Author: fearless_fool,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:26:36

Sí es posible, pero no con los valores de inserción habituales separados por comas.

Prueba esto...

insert into myTable (col1,col2) 
     select aValue as col1,anotherValue as col2 
     union select moreValue,evenMoreValue 
     union...

Sí, es un poco feo pero bastante fácil automatizar la generación de la declaración a partir de un conjunto de valores. Además, parece que solo necesita declarar los nombres de las columnas en la primera selección.

 531
Author: andy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-11-14 12:06:02

Sí, a partir de SQLite 3.7.11 esto es compatible con SQLite. De la documentación SQLite :

Sintaxis de la instrucción SQLite INSERT

(cuando esta respuesta fue escrita originalmente, esto no fue soportado)

Para la compatibilidad con versiones anteriores de SQLite, puede usar el truco sugerido por andy y fearless_fool usando UNION, pero para 3.7.11 y posteriores se debe preferir la sintaxis más simple descrita aquí.

 222
Author: Brian Campbell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:02:59

Escribí un poco de código ruby para generar un único elemento de inserción de varias filas de 500 a partir de una serie de instrucciones insert que era considerablemente más rápido que ejecutar las inserciones individuales. Luego intenté simplemente envolver los múltiples insertos en una sola transacción y descubrí que podía obtener el mismo tipo de velocidad con considerablemente menos código.

BEGIN TRANSACTION;
INSERT INTO table VALUES (1,1,1,1);
INSERT INTO table VALUES (2,2,2,2);
...
COMMIT;
 52
Author: Jamie Cook,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-06 06:26:04

De acuerdo con esta página no es compatible:

  • 2007-12-03: INSERTO de varias filas, también conocido como INSERTO compuesto, no soportado.
  INSERT INTO table (col1, col2) VALUES 
      ('row1col1', 'row1col2'), ('row2col1', 'row2col2'), ...

En realidad, de acuerdo con el estándar SQL92, una expresión de VALORES debería poder pararse sobre sí misma. Por ejemplo, lo siguiente debería devolver una tabla de una columna con tres filas: VALUES 'john', 'mary', 'paul';

A partir de la versión 3.7.11 SQLite hace soporte multi-row-insert. Richard Hipp observaciones:

" El nuevo inserto de múltiples valores es simplemente suger sintáctico (sic) para el compuesto insertar. No hay ventaja de rendimiento de una manera u otra."

 37
Author: typeseven,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-03-20 22:54:11

A partir de la versión 2012-03-20 (3.7.11), sqlite admite la siguiente sintaxis de INSERCIÓN:

INSERT INTO 'tablename' ('column1', 'column2') VALUES
  ('data1', 'data2'),
  ('data3', 'data4'),
  ('data5', 'data6'),
  ('data7', 'data8');

Lea la documentación: http://www.sqlite.org/lang_insert.html

PD: Por favor +1 a la respuesta/respuesta de Brian Campbell. ¡el mío no! Él presentó la solución primero.

 13
Author: mjb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-16 16:13:14

Como han dicho los otros posters, SQLite no soporta esta sintaxis. No se si los insertos compuestos son parte del estándar SQL, pero en mi experiencia están no implementados en muchos productos.

Como un aparte, debe tener en cuenta que el rendimiento de INSERCIÓN en SQLite mejora considerablemente si envuelve múltiples inserciones en una transacción explícita.

 10
Author: Larry Lustig,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-11-14 12:21:19

Sí, sql puede hacer esto, pero con una sintaxis diferente. La documentación sqlite es bastante buena, por cierto. It también le dirá que la única manera de insertar varias filas es use una instrucción select como la fuente de los datos que se insertarán.

 10
Author: innaM,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-27 21:20:25

Sqlite3 no puede hacer eso directamente en SQL excepto a través de un SELECT, y mientras SELECT puede devolver una "fila" de expresiones, no sé cómo hacer que devuelva una columna falsa.

Sin embargo, la CLI puede hacerlo:

.import FILE TABLE     Import data from FILE into TABLE
.separator STRING      Change separator used by output mode and .import

$ sqlite3 /tmp/test.db
SQLite version 3.5.9
Enter ".help" for instructions
sqlite> create table abc (a);
sqlite> .import /dev/tty abc
1
2
3
99
^D
sqlite> select * from abc;
1
2
3
99
sqlite> 

Si coloca un bucle alrededor de una INSERCIÓN, en lugar de usar el comando CLI .import, asegúrese de seguir los consejos en las preguntas frecuentes de sqlite para la velocidad de INSERCIÓN:

Por defecto, cada instrucción INSERT es su propia transacción. Pero si inserto múltiple envolvente instrucción con BEGIN...COMMIT entonces todos los los insertos se agrupan en un solo transacción. El tiempo necesario para comprometerse la transacción se amortiza sobre todos las instrucciones insert adjuntas y así la sentencia time per insert es muy reducido.

Otra opción es ejecutar PRAGMA síncrono = APAGADO. Este comando hacer que SQLite no espere en los datos para alcance la superficie del disco, que hacer que las operaciones de escritura parezcan ser mucho más rápido. Pero si pierdes poder en el en medio de una transacción, su el archivo de base de datos puede dañarse.

 8
Author: DigitalRoss,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-10-22 20:39:15

Alex es correcto: el " select ... la declaración de la unión " perderá el pedido, que es muy importante para algunos usuarios. Incluso cuando inserta en un orden específico, sqlite cambia las cosas, por lo que prefiere usar transacciones si el pedido de inserción es importante.

create table t_example (qid int not null, primary key (qid));
begin transaction;
insert into "t_example" (qid) values (8);
insert into "t_example" (qid) values (4);
insert into "t_example" (qid) values (9);
end transaction;    

select rowid,* from t_example;
1|8
2|4
3|9
 7
Author: AG1,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-06-19 07:11:39

Fearless_fool tiene una gran respuesta para versiones anteriores. Solo quería agregar que debe asegurarse de tener todas las columnas enumeradas. Así que si tiene 3 columnas, debe asegurarse de seleccionar actos en 3 columnas.

Ejemplo: tengo 3 columnas pero solo quiero insertar 2 columnas de datos. Supongamos que no me importa la primera columna porque es un id entero estándar. Podría hacer lo siguiente...

INSERT INTO 'tablename'
      SELECT NULL AS 'column1', 'data1' AS 'column2', 'data2' AS 'column3'
UNION SELECT NULL, 'data3', 'data4'
UNION SELECT NULL, 'data5', 'data6'
UNION SELECT NULL, 'data7', 'data8'

Nota: Recuerde el " seleccionar... declaración del sindicato" perderá la ordenar. (Del GA1)

 7
Author: LEO,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-12-12 17:07:03

No puedes, pero no creo que te pierdas nada.

Debido a que llama a sqlite siempre en proceso, casi no importa en rendimiento si ejecuta 1 instrucción insert o 100 instrucciones insert. Sin embargo, el commit lleva mucho tiempo, así que coloca esos 100 insertos dentro de una transacción.

Sqlite es mucho más rápido cuando se usan consultas parametrizadas (se necesita mucho menos análisis), por lo que no concatenar sentencias grandes como esta:

insert into mytable (col1, col2)
select 'a','b'
union 
select 'c','d'
union ...

Necesitan ser analizados de nuevo y de nuevo porque cada declaración concatenada es diferente.

 6
Author: tuinstoel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-11-14 12:26:26

En mysql lite no se pueden insertar varios valores, pero puede ahorrar tiempo abriendo la conexión solo una vez y luego haciendo todas las inserciones y luego cerrando la conexión. Ahorra mucho tiempo

 6
Author: g.revolution,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-05-21 06:05:17
INSERT INTO TABLE_NAME 
            (DATA1, 
             DATA2) 
VALUES      (VAL1, 
             VAL2), 
            (VAL1, 
             VAL2), 
            (VAL1, 
             VAL2), 
            (VAL1, 
             VAL2), 
            (VAL1, 
             VAL2), 
            (VAL1, 
             VAL2), 
            (VAL1, 
             VAL2), 
            (VAL1, 
             VAL2); 
 6
Author: aasai arun,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-10-11 14:29:56

El problema con el uso de la transacción es que bloquea la tabla también para la lectura. Así que si realmente tiene muchos datos para insertar y necesita acceder a sus datos, por ejemplo, una vista previa o así, de esta manera no funciona bien.

El problema con la otra solución es que se pierde el orden de inserción

insert into mytable (col)
select 'c'
union 
select 'd'
union 
select 'a'
union 
select 'b';

En el sqlite los datos se almacenarán a,b,c,d...

 5
Author: alex,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-07 22:32:13

A partir de la versión 3.7.11 SQLite admite insertos de varias filas. Richard Comentarios Hipp:

Estoy usando 3.6.13

Ordeno así:

insert into xtable(f1,f2,f3) select v1 as f1, v2 as f2, v3 as f3 
union select nextV1+, nextV2+, nextV3+

Con 50 registros insertados a la vez, solo toma un segundo o menos.

Es cierto que usar sqlite para insertar varias filas a la vez es muy posible. Por @Andy escribió.

Gracias Andy + 1

 5
Author: XenKid,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-06-04 18:21:46
INSERT INTO tabela(coluna1,coluna2) 
SELECT 'texto','outro'
UNION ALL 
SELECT 'mais texto','novo texto';
 4
Author: ademar111190,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-08-05 23:22:15

Si utiliza el complemento Sqlite manager firefox, admite inserciones masivas de sentencias SQL INSERT.

De hecho no soporta esto, pero Sqlite Browser lo hace (funciona en Windows, OS X, Linux)

 2
Author: Chris S,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-28 00:28:43

Tengo una consulta como la siguiente, pero con el controlador ODBC SQLite tiene un error con "," dice. Corro vbscript en HTA (Aplicación Html).

INSERT INTO evrak_ilac_iliskileri (evrak_id, ilac_id, baglayan_kullanici_id, tarih) VALUES (4150,762,1,datetime()),(4150,9770,1,datetime()),(4150,6609,1,datetime()),(4150,3628,1,datetime()),(4150,9422,1,datetime())
 2
Author: caglaror,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-10-21 19:48:02

En sqlite 3.7.2:

INSERT INTO table_name (column1, column2) 
                SELECT 'value1', 'value1' 
          UNION SELECT 'value2', 'value2' 
          UNION SELECT 'value3', 'value3' 

Y así sucesivamente

 2
Author: ashakirov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-03-17 14:29:07

Puedo hacer que la consulta sea dinámica. Esta es mi mesa:

CREATE TABLE "tblPlanner" ("probid" text,"userid" TEXT,"selectedtime" DATETIME,"plannerid" TEXT,"isLocal" BOOL,"applicationid" TEXT, "comment" TEXT, "subject" TEXT)

Y estoy obteniendo todos los datos a través de un JSON, así que después de obtener todo dentro de un NSArray seguí esto:

    NSMutableString *query = [[NSMutableString alloc]init];
    for (int i = 0; i < arr.count; i++)
    {
        NSString *sqlQuery = nil;
        sqlQuery = [NSString stringWithFormat:@" ('%@', '%@', '%@', '%@', '%@', '%@', '%@', '%@'),",
                    [[arr objectAtIndex:i] objectForKey:@"plannerid"],
                    [[arr objectAtIndex:i] objectForKey:@"probid"],
                    [[arr objectAtIndex:i] objectForKey:@"userid"],
                    [[arr objectAtIndex:i] objectForKey:@"selectedtime"],
                    [[arr objectAtIndex:i] objectForKey:@"isLocal"],
                    [[arr objectAtIndex:i] objectForKey:@"subject"],
                    [[arr objectAtIndex:i] objectForKey:@"comment"],
                    [[NSUserDefaults standardUserDefaults] objectForKey:@"applicationid"]
                    ];
        [query appendString:sqlQuery];
    }
    // REMOVING LAST COMMA NOW
    [query deleteCharactersInRange:NSMakeRange([query length]-1, 1)];

    query = [NSString stringWithFormat:@"insert into tblPlanner (plannerid, probid, userid, selectedtime, isLocal, applicationid, subject, comment) values%@",query];

Y finalmente la consulta de salida es la siguiente:

insert into tblPlanner (plannerid, probid, userid, selectedtime, isLocal, applicationid, subject, comment) values 
<append 1>
('pl1176428260', '', 'US32552', '2013-06-08 12:00:44 +0000', '0', 'subj', 'Hiss', 'ap19788'),
<append 2>
('pl2050411638', '', 'US32552', '2013-05-20 10:45:55 +0000', '0', 'TERI', 'Yahoooooooooo', 'ap19788'), 
<append 3>
('pl1828600651', '', 'US32552', '2013-05-21 11:33:33 +0000', '0', 'test', 'Yest', 'ap19788'),
<append 4>
('pl549085534', '', 'US32552', '2013-05-19 11:45:04 +0000', '0', 'subj', 'Comment', 'ap19788'), 
<append 5>
('pl665538927', '', 'US32552', '2013-05-29 11:45:41 +0000', '0', 'subj', '1234567890', 'ap19788'), 
<append 6>
('pl1969438050', '', 'US32552', '2013-06-01 12:00:18 +0000', '0', 'subj', 'Cmt', 'ap19788'),
<append 7>
('pl672204050', '', 'US55240280', '2013-05-23 12:15:58 +0000', '0', 'aassdd', 'Cmt', 'ap19788'), 
<append 8>
('pl1019026150', '', 'US32552', '2013-06-08 12:15:54 +0000', '0', 'exists', 'Cmt', 'ap19788'), 
<append 9>
('pl790670523', '', 'US55240280', '2013-05-26 12:30:21 +0000', '0', 'qwerty', 'Cmt', 'ap19788')

Que se está ejecutando bien a través de código también y soy capaz de guardar todo en SQLite con éxito.

Antes de esto hice que UNION las consultas fueran dinámicas, pero eso comenzó a dar algún error de sintaxis. De todos modos, esto está funcionando bien para me.

 2
Author: Vaibhav Saran,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-16 08:42:07

Me sorprende que nadie haya mencionado declaraciones preparadas. A menos que esté utilizando SQL por su cuenta y no dentro de cualquier otro lenguaje, entonces yo pensaría que declaraciones preparadas envueltas en una transacción sería la forma más eficiente de insertar varias filas.

 1
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-12 10:11:08
 0
Author: Mahmoud Badri,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-09-26 22:30:00

Si estás usando bash shell puedes usar esto:

time bash -c $'
FILE=/dev/shm/test.db
sqlite3 $FILE "create table if not exists tab(id int);"
sqlite3 $FILE "insert into tab values (1),(2)"
for i in 1 2 3 4; do sqlite3 $FILE "INSERT INTO tab (id) select (a.id+b.id+c.id)*abs(random()%1e7) from tab a, tab b, tab c limit 5e5"; done; 
sqlite3 $FILE "select count(*) from tab;"'

O si estás en sqlite CLI, entonces necesitas hacer esto:

create table if not exists tab(id int);"
insert into tab values (1),(2);
INSERT INTO tab (id) select (a.id+b.id+c.id)*abs(random()%1e7) from tab a, tab b, tab c limit 5e5;
INSERT INTO tab (id) select (a.id+b.id+c.id)*abs(random()%1e7) from tab a, tab b, tab c limit 5e5;
INSERT INTO tab (id) select (a.id+b.id+c.id)*abs(random()%1e7) from tab a, tab b, tab c limit 5e5;
INSERT INTO tab (id) select (a.id+b.id+c.id)*abs(random()%1e7) from tab a, tab b, tab c limit 5e5;
select count(*) from tab;

¿Cómo funciona? Hace uso de esa tabla if tab:

id int
------
1
2

Luego select a.id, b.id from tab a, tab b devuelve

a.id int | b.id int
------------------
    1    | 1
    2    | 1
    1    | 2
    2    | 2

Y así sucesivamente. Después de la primera ejecución insertamos 2 filas, luego 2^3 = 8. (tres porque tenemos tab a, tab b, tab c)

Después de la segunda ejecución insertamos filas adicionales (2+8)^3=1000

Después insertamos alrededor de max(1000^3, 5e5)=500000 filas y así en...

Este es el método más rápido conocido para mí de poblar la base de datos SQLite.

 -1
Author: test30,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-28 15:02:15