Est-il possible d'insérer plusieurs lignes à la fois dans une base de données SQLite?

dans MySQL vous pouvez insérer plusieurs lignes comme ceci:

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

cependant, je reçois une erreur quand j'essaie de faire quelque chose comme ça. Est-il possible d'insérer plusieurs lignes à la fois dans une base de données SQLite? Quelle est la syntaxe pour le faire?

493
demandé sur Andrew 2009-10-23 00:04:42

24 réponses

mise à jour

Comme BrianCampbell points ici , SQLite 3.7.11 et ci-dessus prend désormais en charge la plus simple, la syntaxe de l'original post . Cependant, l'approche montrée est toujours appropriée si vous voulez un maximum de compatibilité entre les bases de données existantes.

réponse originale

si j'avais des privilèges, je changerais la réponse d'andy : vous peut insérez plusieurs lignes dans SQLite, vous avez juste besoin de syntaxe différente . Pour être parfaitement clair, L'exemple de L'OPs MySQL:

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

ce qui peut être refondu en SQLite comme:

     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'

une note sur les performances

j'ai utilisé à l'origine cette technique pour charger efficacement de grands ensembles de données de Ruby on Rails. cependant , comme le souligne Jaime Cook , il n'est pas clair qu'il s'agit d'un emballage plus rapide individu INSERTs dans le cadre d'une seule transaction:

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

si l'efficacité est votre but, vous devriez essayer cela d'abord.

a note on UNION vs UNION ALL

comme plusieurs personnes ont commenté, si vous utilisez UNION ALL (comme montré ci-dessus), toutes les lignes seront insérées, donc dans ce cas, vous obtiendrez quatre lignes de data1, data2 . Si vous omettez le ALL , alors dupliquez les rangées seront éliminées (et l'opération sera probablement un peu plus lente). Nous utilisons le syndicat car il correspond mieux à la sémantique du post original.

en conclusion

P. S.: Merci de +1 andy " répondre , pas le mien! Il a présenté la solution première.

559
répondu fearless_fool 2017-05-23 12:26:36

Oui c'est possible, mais pas avec les valeurs habituelles d'insertion séparées par des virgules.

essayez ceci...

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

Oui, c'est un peu laid mais assez facile pour automatiser la génération de la déclaration à partir d'un ensemble de valeurs. En outre, il semble que vous devez seulement déclarer les noms de colonne dans le premier select.

531
répondu andy 2009-11-14 12:06:02

Oui, comme de SQLite 3.7.11 ceci est pris en charge dans SQLite. De la documentation SQLite :

SQLite INSERT statement syntax

(lorsque cette réponse a été écrite à l'origine, elle n'était pas supportée)

pour la compatibilité avec les anciennes versions de SQLite, vous pouvez utiliser le truc suggéré par andy et fearless_fool en utilisant UNION , mais pour 3.7.11 et plus tard la syntaxe plus simple décrite ici devrait être préférée.

222
répondu Brian Campbell 2017-05-23 12:02:59

j'ai écrit un code ruby pour générer un insert simple de 500 éléments à plusieurs rangées à partir d'une série d'instructions insert qui était considérablement plus rapide que l'exécution des inserts individuels. Puis j'ai simplement essayé d'emballer les inserts multiples dans une seule transaction et j'ai trouvé que je pouvais obtenir le même genre d'accélération avec beaucoup moins de code.

BEGIN TRANSACTION;
INSERT INTO table VALUES (1,1,1,1);
INSERT INTO table VALUES (2,2,2,2);
...
COMMIT;
52
répondu Jamie Cook 2011-03-06 06:26:04

Selon cette page il n'est pas pris en charge:

  • 2007-12-03 : Multi-row INSERT A. K. A. INSERT composé non supporté.
  INSERT INTO table (col1, col2) VALUES 
      ('row1col1', 'row1col2'), ('row2col1', 'row2col2'), ...

en fait, selon la norme SQL92, une expression de valeurs devrait pouvoir se tenir debout sur elle-même. Par exemple, le suivant devrait retourner un tableau d'une colonne avec trois lignes: VALUES 'john', 'mary', 'paul';

à partir de la version 3.7.11 SQLite ne support multi-insertion de ligne . Richard Hipp commente:

"Le nouveau multi-valuées insert est purement syntaxique suger (sic) pour le composé insérer. Il n'y a pas d'avantage de performance d'une façon ou d'une autre."

37
répondu typeseven 2012-03-20 22:54:11

commencer de la version 2012-03-20( 3.7.11), sqlite soutenir la syntaxe D'insertion suivante:

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

Lire la documentation: http://www.sqlite.org/lang_insert.html

PS: Merci de +1 à Brian Campbell réponse/réponse. pas le mien! Il a présenté la solution première.

13
répondu mjb 2013-05-16 16:13:14

comme l'ont dit les autres posters, SQLite ne supporte pas cette syntaxe. Je ne sais pas si les inserts composés font partie de la norme SQL, mais d'après mon expérience ils sont pas mis en œuvre dans de nombreux produits.

comme mise de côté, vous devriez être conscient que la performance D'insertion dans SQLite est considérablement améliorée si vous enveloppez plusieurs INSERTs dans une transaction explicite.

10
répondu Larry Lustig 2009-11-14 12:21:19

Oui, sql peut le faire, mais avec une syntaxe différente. Le documentation sqlite est assez bon, d'ailleurs. Il vous dira aussi que la seule façon d'insérer plusieurs lignes est utilisez une instruction select comme source des données à insérer.

10
répondu innaM 2015-04-27 21:20:25

Sqlite3 ne peut pas faire cela directement en SQL sauf via un SELECT, et bien que SELECT puisse retourner une "rangée" d'expressions, Je ne connais aucun moyen de le faire retourner une colonne bidon.

cependant, le CLI peut le faire:

.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 vous mettez une boucle autour D'un INSERT, plutôt que d'utiliser la commande CLI .import , alors assurez-vous de suivre les conseils dans la FAQ sqlite pour INSERT speed:

par défaut, chaque insertion l'énoncé est sa propre transaction. Mais si vous surround plusieurs instructions INSERT avec COMMENCER...S'ENGAGER ensuite tous les les inserts sont groupés en un seul transaction. Le temps nécessaire pour s'engager la transaction est amortie sur l'ensemble l'encart ci-joint déclarations et l'indication de temps par insertion est considérablement réduit.

une autre option est D'exécuter PRAGMA synchrone=OFF. Cette commande faire en sorte que SQLite n'attende pas les atteindre la surface du disque, qui effectuer les opérations d'écriture semblent être beaucoup plus rapide. Mais si vous perdez du pouvoir dans au milieu d'une transaction, vos fichier de base de données peut aller corrompus.

8
répondu DigitalRoss 2009-10-22 20:39:15

Alex a raison: le " select ... déclaration union " perdra l'ordre qui est très important pour certains utilisateurs. Même lorsque vous insérez dans un ordre spécifique, sqlite change les choses et préfère utiliser des transactions si l'ordre insert est important.

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
répondu AG1 2012-06-19 07:11:39

fearless_fool a une grande réponse pour les versions plus anciennes. Je voulais juste ajouter que vous devez vous assurer que vous avez toutes les colonnes mentionnées. Donc, si vous avez 3 colonnes, vous devez assurez-vous de sélectionner agit sur 3 colonnes.

Exemple: j'ai 3 colonnes mais je ne veux insérer 2 colonnes de données. Supposons que je ne me soucie pas de la première colonne parce que c'est un id entier standard. Je pourrais faire la suite...

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'

Note: "sélectionner. .. déclaration de l'union perdra l'ordre. (À partir de AG1)

7
répondu LEO 2012-12-12 17:07:03

vous ne pouvez pas mais je ne pense pas que vous manquez quelque chose.

parce que vous appelez sqlite toujours en processus, il n'a presque pas d'importance dans la performance si vous exécutez 1 insert statement ou 100 insert statements. Le commit prend cependant beaucoup de temps, alors mettez ces 100 inserts dans une transaction.

Sqlite est beaucoup plus rapide quand vous utilisez des requêtes paramétrées (beaucoup moins parsing nécessaire) donc je ne concaténerai pas de grandes déclarations comme ceci:

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

ils doivent être analysés encore et encore parce que chaque déclaration concaténée est différente.

6
répondu tuinstoel 2009-11-14 12:26:26

dans mysql lite vous ne pouvez pas insérer plusieurs valeurs, mais vous pouvez gagner du temps en ouvrant la connexion une seule fois, puis en faisant toutes les insertions et en fermant la connexion. Il économise beaucoup de temps

6
répondu g.revolution 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
répondu aasai arun 2012-10-11 14:29:56

le problème avec l'utilisation de transaction est que vous verrouiller la table aussi pour la lecture. Donc si vous avez vraiment beaucoup de données à insérer et que vous avez besoin d'accéder à vos données, par exemple un aperçu ou plus, cette façon ne fonctionne pas bien.

Le problème avec l'autre solution est que vous perdez de l'ordre de l'insertion

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

dans le sqlite les données seront stockées A,b,C,D...

5
répondu alex 2011-03-07 22:32:13

à partir de la version 3.7.11 SQLite ne soutient multi-ligne-insert. Richard Commentaires de Hipp:

j'utilise 3.6.13

je commande comme ceci:

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

avec 50 enregistrements insérés à la fois, ça ne prend qu'une seconde ou moins.

C'est vrai utilisant sqlite pour insérer plusieurs lignes à la fois est très possible. Par @Andy a écrit.

merci Andy +1

5
répondu XenKid 2012-06-04 18:21:46
INSERT INTO tabela(coluna1,coluna2) 
SELECT 'texto','outro'
UNION ALL 
SELECT 'mais texto','novo texto';
4
répondu ademar111190 2011-08-05 23:22:15

si vous utilisez le Sqlite manager plugin firefox, il prend en charge les inserts en vrac à partir de INSERT énoncés SQL.

Enfait il ne supporte pas cela, mais Sqlite Browser (fonctionne sur Windows, OS X, Linux)

2
répondu Chris S 2010-01-28 00:28:43

j'ai une requête comme ci-dessous, mais avec ODBC driver SQLite a une erreur avec", " il dit. J'exécute vbscript dans HTA (application 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
répondu caglaror 2012-10-21 19:48:02

sur sqlite 3.7.2:

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

et ainsi de suite

2
répondu ashakirov 2013-03-17 14:29:07

je suis capable de rendre la requête dynamique. Voici ma table:

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

et j'obtiens toutes les données à travers un JSON , donc après avoir obtenu tout à l'intérieur d'un NSArray j'ai suivi ceci:

    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];

et finalement la requête de sortie est la suivante:

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')

qui fonctionne bien à travers le code aussi et je suis capable de tout enregistrer en SQLite avec succès.

avant cela j'ai fait UNION truc de requête dynamique mais qui a commencé à donner une erreur de syntaxe. De toute façon, cela fonctionne bien pour moi.

2
répondu Vaibhav Saran 2013-05-16 08:42:07

je suis surpris que personne n'ait mentionné déclarations préparées . À moins que vous n'utilisiez SQL seul et pas dans une autre langue, alors je penserais que déclarations préparées enveloppées dans une "transaction serait le moyen le plus efficace d'insérer des lignes multiples.

1
répondu 2014-04-12 10:11:08
0
répondu Mahmoud Badri 2013-09-26 22:30:00

si vous utilisez bash shell vous pouvez utiliser ceci:

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;"'

ou si vous êtes dans sqlite CLI, alors vous devez faire ceci:

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;

comment ça marche? Il fait usage de cela si la table tab :

id int
------
1
2

puis select a.id, b.id from tab a, tab b retourne

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

et ainsi de suite. Après la première exécution nous insérons 2 lignes, puis 2^3=8. (trois parce que nous avons tab a, tab b, tab c )

après la deuxième exécution, nous insérons (2+8)^3=1000 lignes supplémentaires

Aftern thrid nous insérons environ max(1000^3, 5e5)=500000 lignes et ainsi de suite...

C'est la méthode la plus rapide connue pour moi de peupler la base de données SQLite.

-1
répondu test30 2014-07-28 15:02:15