web-dev-qa-db-fra.com

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 lorsque 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?

525
Andrew

mise à jour

Comme BrianCampbell indique ici , SQLite 3.7.11 et les versions ultérieures prennent désormais en charge la syntaxe plus simple du message d'origine . Toutefois, l'approche indiquée reste appropriée si vous souhaitez une compatibilité maximale entre bases de données héritées.

réponse originale

Si j'avais des privilèges, je bumpais réponse d'Andy : Vous pouvez insérer plusieurs lignes dans SQLite, vous avez juste besoin de syntaxe différente . Pour que ce soit parfaitement clair, l'exemple MySQL des PO:

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

Ceci peut être refait dans 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 la performance

J'ai initialement utilisé cette technique pour charger efficacement de grands ensembles de données à partir de Ruby sur Rails. Cependant , comme le souligne Jaime Cook , il n’est pas clair qu’il soit plus rapide d’envelopper un individu INSERTs dans un seul transaction:

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

Si votre objectif est l'efficacité, essayez-le d'abord.

une note sur UNION vs UNION ALL

Comme plusieurs personnes l'ont commenté, si vous utilisez UNION ALL (comme indiqué ci-dessus), toutes les lignes seront insérées. Dans ce cas, vous obtiendrez alors quatre lignes de data1, data2. Si vous omettez le ALL, les lignes en double seront éliminées (et l'opération sera probablement un peu plus lente). Nous utilisons UNION ALL car il correspond plus étroitement à la sémantique du message d'origine.

en terminant

P.S .: S'il vous plaît +1 réponse d'Andy , pas la mienne! Il a présenté la solution en premier.

590
fearless_fool

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

Essaye ça...

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

Oui, il est un peu moche mais assez facile d'automatiser la génération de l'instruction à partir d'un ensemble de valeurs. En outre, il apparaît que vous devez uniquement déclarer les noms de colonne dans la première sélection.

551
andy

Oui, à partir de SQLite .7.11 ceci est supporté dans SQLite. De la documentation SQLite :

SQLite INSERT statement syntax

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

Pour assurer la compatibilité avec les anciennes versions de SQLite, vous pouvez utiliser l’astuce suggérée par andy et fearless_fool en utilisant UNION, mais pour 3.7.11 et les versions ultérieures, la syntaxe plus simple décrite dans ici devrait être préféré.

233
Brian Campbell

J'ai écrit du code Ruby pour générer une insertion d'insert à plusieurs lignes de 500 éléments à partir d'une série d'instructions d'insertion, ce qui était considérablement plus rapide que l'exécution des insertions individuelles. Ensuite, j'ai simplement essayé de regrouper les multiples insertions dans une seule transaction et de constater que je pouvais atteindre le même type de vitesse avec beaucoup moins de code.

BEGIN TRANSACTION;
INSERT INTO table VALUES (1,1,1,1);
INSERT INTO table VALUES (2,2,2,2);
...
COMMIT;
57
Jamie Cook

Selon cette page ce n'est pas supporté:

  • 2007-12-03: INSERT à plusieurs rangées a.k.a composé INSERT non pris en charge.
  INSERT INTO table (col1, col2) VALUES 
      ('row1col1', 'row1col2'), ('row2col1', 'row2col2'), ...

En fait, selon le standard SQL92, une expression VALUES devrait pouvoir se tenir sur elle-même. Par exemple, les éléments suivants doivent renvoyer une table à une colonne avec trois lignes: VALUES 'john', 'mary', 'paul';

A partir de la version 3.7.11, SQLite prend en charge multi-row-insert . Richard Hipp a commenté:

"La nouvelle insertion à valeurs multiples est simplement une syntaxe syntaxique (sic) pour l'insertion composée. Il n'y a aucun avantage en termes de performances d'une manière ou d'une autre."

37
typeseven

Depuis la version 2012-03-20 (3.7.11), sqlite prend en charge la syntaxe INSERT 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: S'il vous plaît +1 à la réponse/réponse de Brian Campbell. pas le mien! Il a présenté la solution en premier.

14
mjb

Oui, SQL peut le faire, mais avec une syntaxe différente. Le documentation sqlite est plutôt bon, au fait. Il vous dira aussi que le seul moyen d'insérer plusieurs lignes est d'utiliser une instruction select comme source des données être inséré.

10
innaM

Comme l'ont dit d'autres afficheurs, SQLite ne prend pas en charge cette syntaxe. Je ne sais pas si les INSERT composés font partie du standard SQL, mais d'après mon expérience, ils sont non implémentés dans de nombreux produits.

Soit dit en passant, vous devez savoir que les performances INSERT dans SQLite sont considérablement améliorées si vous encapsulez plusieurs INSERT dans une transaction explicite.

10
Larry Lustig

Sqlite3 ne peut le faire directement en SQL que via un SELECT, et alors que SELECT peut renvoyer une "rangée" d'expressions, je ne connais aucun moyen de lui faire renvoyer une colonne factice.

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 placez une boucle autour d'un INSERT plutôt que d'utiliser la commande CLI .import, veillez à suivre les conseils donnés dans sqlite FAQ pour la vitesse INSERT:

Par défaut, chaque instruction INSERT est sa propre transaction. Mais si vous entourez plusieurs instructions INSERT avec BEGIN ... COMMIT, toutes les insertions sont regroupées dans une seule transaction. Le temps nécessaire pour valider la transaction est amorti sur toutes les instructions insert incluses, ce qui permet de réduire considérablement l’instruction time par insert.

Une autre option consiste à exécuter PRAGMA synchrone = OFF. Grâce à cette commande, SQLite n'attendra pas que les données atteignent la surface du disque, ce qui rendra les opérations d'écriture plus rapides. Mais si vous perdez le pouvoir au milieu d'une transaction, votre fichier de base de données peut être corrompu.

8
DigitalRoss

fearless_fool a une excellente réponse pour les anciennes versions. Je voulais juste ajouter que vous devez vous assurer que toutes les colonnes sont répertoriées. Donc, si vous avez 3 colonnes, vous devez vous assurer que select agit sur 3 colonnes.

Exemple: J'ai 3 colonnes mais je veux seulement insérer 2 colonnes de données. Supposons que je me fiche de la première colonne car il s'agit d'un identifiant entier standard. Je pourrais faire ce qui suit ...

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'

Remarque: N'oubliez pas que l'instruction "select ... union" perd la commande. (De AG1)

8
LEO

Alex a raison: la déclaration "select ... union" perd la commande, ce qui est très important pour certains utilisateurs. Même lorsque vous insérez dans un ordre spécifique, sqlite change les choses, préférez donc utiliser des transactions si la commande d'insertion est 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
8
AG1
INSERT INTO TABLE_NAME 
            (DATA1, 
             DATA2) 
VALUES      (VAL1, 
             VAL2), 
            (VAL1, 
             VAL2), 
            (VAL1, 
             VAL2), 
            (VAL1, 
             VAL2), 
            (VAL1, 
             VAL2), 
            (VAL1, 
             VAL2), 
            (VAL1, 
             VAL2), 
            (VAL1, 
             VAL2); 
7
aasai arun

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 effectuant toutes les insertions, puis en fermant la connexion. Ça fait gagner beaucoup de temps

6
g.revolution

Vous ne pouvez pas mais je ne pense pas que rien ne vous manque.

Comme vous appelez toujours sqlite dans le processus, peu importe la performance, que vous exécutiez une instruction insert ou 100 instructions insert. Cependant, le commit prend beaucoup de temps, alors mettez ces 100 insertions dans une transaction.

Sqlite est beaucoup plus rapide lorsque vous utilisez des requêtes paramétrées (beaucoup moins d’analyses nécessaires), donc je ne concaténerais pas de grandes instructions comme celle-ci:

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

Ils doivent être analysés encore et encore, car chaque déclaration concaténée est différente.

6
tuinstoel

Le problème de l'utilisation de transaction est que vous verrouillez également la table en lecture. Donc, si vous avez vraiment beaucoup de données à insérer et que vous devez accéder à vos données, par exemple un aperçu ou autre, cette méthode ne fonctionne pas bien.

Le problème avec l’autre solution est que vous perdez l’ordre d’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
alex

A partir de la version 3.7.11, SQLite prend en charge l’insertion sur plusieurs lignes. Richard Hipp a commenté:

J'utilise 3.6.13

Je commande comme ça:

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, cela ne prend qu'une seconde ou moins.

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

merci Andy +1

5
XenKid
INSERT INTO tabela(coluna1,coluna2) 
SELECT 'texto','outro'
UNION ALL 
SELECT 'mais texto','novo texto';
4
ademar111190

J'ai une requête comme ci-dessous, mais avec ODBC, le pilote SQLite a une erreur avec "," il est écrit. Je lance 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
caglaror

Je suis capable de rendre la requête dynamique. Ceci est ma table:

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

et je reçois toutes les données à travers un JSON, donc après avoir tout contenu dans 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 enfin, 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 aussi avec le code et je suis capable de tout sauvegarder dans SQLite avec succès.

Avant cela, j’ai rendu la requête UNION dynamique, mais cela a commencé à donner une erreur de syntaxe. Quoi qu'il en soit, cela fonctionne bien pour moi.

2
Vaibhav Saran

Si vous utilisez le plugin Sqlite manager firefox, il prend en charge les insertions en bloc à partir d'instructions INSERT SQL.

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

2
Chris S

Sur sqlite 3.7.2:

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

etc

2
ashakirov

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 instructions préparées enveloppé dans un transaction serait le moyen le plus efficace d'insérer plusieurs lignes .

1
user918938

vous pouvez utiliser InsertHelper, c'est facile et rapide

documentation: http://developer.Android.com/reference/Android/database/DatabaseUtils.InsertHelper.html

tutoriel: http://www.outofwhatbox.com/blog/2010/12/Android-using-databaseutils-inserthelper-for-faster-insertions-into-sqlite-database/

Edit: InsertHelper est obsolète à partir du niveau 17 de l'API

0
Mahmoud Badri