Bir SQLite veritabanına aynı anda birden çok satır eklemek mümkün müdür?


551

MySQL'de böyle birden çok satır ekleyebilirsiniz:

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

Ancak, böyle bir şey yapmaya çalıştığımda bir hata alıyorum. Bir SQLite veritabanına aynı anda birden çok satır eklemek mümkün müdür? Bunu yapmak için sözdizimi nedir?


26
Bu soru, genel olarak SQL'in aksine özellikle SQLite hakkında sorduğu için bir dupe değil (bu soruya verilen cevapların bazıları bu konuda yardımcı olsa da).
Brian Campbell

5
Toplu
eklerde

5
Soru, bunu neden yapmanız gerektiğidir. SQlite aynı makinede işlemde olduğundan ve ihtiyacını görmediğim bir işleme birden fazla kesici uç ekleyebilir misiniz?
andig

2
Evet, 2012-03-20 (3.7.11) sürümünden başlayın, sözdiziminiz desteklenmektedir.
mjb

Yanıtlar:


607

Güncelleme

As BrianCampbell burada işaret , 3.7.11 SQLite ve yukarıdaki artık orijinal yazının daha basit sözdizimi destekler . Ancak, eski veritabanları arasında maksimum uyumluluk istiyorsanız, gösterilen yaklaşım yine de uygundur.

orijinal cevap

Ben ayrıcalıkları olsaydı, vurmayı tercih ederim nehir cevap : Sen edebilirsiniz SQLite'ta birden çok satır eklemek, sadece ihtiyaç farklı bir sözdizimi . Mükemmel bir şekilde açıklamak gerekirse, OPs MySQL örneği:

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

Bu SQLite içine yeniden olabilir:

     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'

performans hakkında bir not

Başlangıçta bu tekniği Ruby on Rails'den büyük veri kümelerini verimli bir şekilde yüklemek için kullandım. Bununla birlikte , Jaime Cook'un belirttiği gibi , bunun INSERTstek bir işlemde daha hızlı sarma yapan bir kişi olduğu açık değildir :

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

Verimlilik hedefinizse, önce bunu denemelisiniz.

UNION ve UNION ALL hakkında bir not

Birkaç kişinin yorumladığı gibi, UNION ALL(yukarıda gösterildiği gibi) kullanırsanız, tüm satırlar eklenir, bu durumda bu durumda dört satır alırsınız data1, data2. Atlarsanız, ALLyinelenen satırlar elenir (ve işlem muhtemelen biraz daha yavaş olur). Orijinal gönderinin anlambilimine daha yakın olduğundan UNION ALL'u kullanıyoruz.

kapanışta

Not: Lütfen ilk önce çözümü sunduğu için nehrin cevabını + 1'leyin .


102
Bir başka not olarak, sqlite sorgu başına sadece 500'e kadar bu tür birliği seçmeyi destekliyor gibi görünüyor, bu yüzden daha fazla veri atmaya çalışıyorsanız, bunu 500 element bloğuna bölmeniz gerekecek ( sqlite.org/limits.html )
Jamie Cook

3
Kabul edildi: SQLite darboğaz değil, bireysel ORM işlemlerinin (benim durumumda Ruby On Rails) yüküdür. Yani hala büyük bir kazanç.
fearless_fool

3
Bu çözüm veya 3.7.11 çözümü işlem bloklarını kullanma ile nasıl karşılaştırılır? daha hızlı mı insert into t values (data),(data),(data)yoksa begin transaction; insert into t values (data);insert into t values (data);insert into t values (data);Commit;?
Dan

5
Başka bir not olarak: dikkatli olun! bu sözdizimi yinelenen satırları kaldırır! bundan UNION ALLkaçınmak için (veya bazı küçük performans kazançları için) kullanın.
chacham15

1
@Shadowfax, SQLite sürümünü kontrol etmek için sqlite3.sqlite_version( bakın 3.7.x veya 3.8.x olmalıdır) değil sqlite3.version(sadece python modülünün sürümü).
max

562

Evet mümkündür, ancak normal virgülle ayrılmış kesici uç değerlerinde değildir.

Bunu dene...

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

Evet, ifadenin oluşturulmasını bir dizi değerden otomatikleştirmek için biraz çirkin ama kolay. Ayrıca, yalnızca ilk seçimde sütun adlarını bildirmeniz gerekir.


36
kullanın UNION ALLdeğil UNION. Yinelenenleri kaldırmak istiyorsanız hariç.
Benoit

4
Kimliklerin otomatik olarak artırılmasını istiyorsanız, onlara bir NULL değeri verin.
lenooh

241

Evet, SQLite 3.7.11'den itibaren bu SQLite'de desteklenmektedir. Gönderen SQLite belgeler :

SQLite INSERT deyimi sözdizimi

(bu cevap ilk olarak yazıldığında, bu desteklenmemiştir)

SQLite'nin eski sürümleriyle uyumluluk için, andy ve fearless_fool tarafından önerilen hileyi kullanarak kullanabilirsiniz UNION, ancak 3.7.11 ve sonraki sürümler için burada açıklanan daha basit sözdizimi tercih edilmelidir.


3
Diyagramın birden fazla satıra izin verdiğini söyleyebilirim, çünkü sonra parantezlerin dışında bir virgül ile kapalı bir döngü var VALUES.
Johannes Gerer

@JohannesGerer Yerleştirdiğimden beri bu resmi güncellediler. Diyagramı İnternet Arşivi'ne eklediğim anda görebilirsiniz . Aslında, sadece iki ay önce bir ekte birden çok satır için destek eklediler ve sadece iki gün önce bu değişiklikle bir sürüm yayınladılar. Cevabımı buna göre güncelleyeceğim.
Brian Campbell

1
@Brian, bu o devletler, SQLite dokümantasyon metnini alıntı misiniz IS mümkün? Dokümanları 3 kez tekrar okudum ve birden çok satır VALUES (...), (...)
eklemeyle

1
@Prizoff Test destekleri de dahil olmak üzere, bu desteğin eklendiği taahhütle bağlantı kurdum . Diyagramda ( IA bağlantısını karşılaştırın ), ifadenin çevresinde VALUESvirgülle ayrılarak tekrarlanabileceğini gösteren bir döngü olduğunu görebilirsiniz. Ve "VALUES yantümcesi aracılığıyla birden çok satır eklenmesine izin vermek için INSERT sözdizimini geliştirin" ifadesini içeren özellik ekleyen sürümün sürüm notlarına bağlandım .
Brian Campbell

1
Ben SQLite bakıcıya bu sözü @Prizoff, o gelmiştir bir düzeltme işlenen olduğu taslak belgelerinde mevcut . Bir sonraki sürümden itibaren resmi belgelerde olacağını tahmin ediyorum.
Brian Campbell

57

Bireysel insertleri çalıştırmaktan çok daha hızlı bir insert deyiminden tek bir 500 elementli çok satırlı insert oluşturmak için bazı yakut kodu yazdım. Sonra sadece tek bir işlem içine birden fazla ekler sarma denedim ve ben oldukça az kod ile hız aynı tür alabilirsiniz bulundu.

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

1
ancak doğrudan SQLite yöneticisinde çalışırken kodda çalışmadı.
Kodda

4
Benim kod eklemek bu tarzı kullanıyorum ve mükemmel çalışıyor. Sadece TÜM SQL'i bir kerede gönderdiğinizden emin olmanız gerekir. Bu benim için büyük bir hız artışı oldu, ancak kabul edilen cevabın bundan daha hızlı mı yoksa daha yavaş mı olduğunu merak ediyorum?
Dan

Bu yaklaşım, tek bir işlemde birden çok tabloyu değiştirirken gerçekten iyi ölçeklenir, bu da bir veritabanını toplu yüklerken kendimi sık sık yapıyor.
Frank

Bağlamaları kullanmanız gerekiyorsa bu yaklaşımın işe yaramayacağını unutmayın . SQLite3 Engine, tüm bağlarınızın ilk deyime uygulanacağını varsayar ve aşağıdaki deyimleri yok sayar. Daha ayrıntılı bir açıklama için bu SO sorusuna bakın .
Philippe Hebert

38

Bu sayfaya göre desteklenmiyor:

  • 2007-12-03: Çok satırlı INSERT olarak da adlandırılan bileşik INSERT desteklenmiyor.
  INSERT INTO table (col1, col2) VALUES 
      ('row1col1', 'row1col2'), ('row2col1', 'row2col2'), ...

Aslında, SQL92 standardına göre, bir VALUES ifadesi kendi üzerinde durabilmelidir. Örneğin, aşağıdakiler üç satırlı tek sütunlu bir tablo döndürmelidir:VALUES 'john', 'mary', 'paul';

Sürümü 3.7.11 itibariyle SQLite yapar desteği çoklu satır-insert . Richard Hipp şöyle diyor:

Diyerek şöyle devam etti: "Yeni çok değerli insert, bileşik insert için sadece sözdizimsel şekerdir (sic). Şu ya da bu şekilde performans avantajı yoktur."


Şu ya da bu şekilde performans avantajı yoktur. - Bu sözleri nerede gördüğünü söyleyebilir misin? Hiçbir yerde bulamadım.
Alix Axel

15

2012-03-20 (3.7.11) sürümünden başlayarak sqlite aşağıdaki INSERT sözdizimini destekler:

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

Belgeleri okuyun: http://www.sqlite.org/lang_insert.html

Not: Lütfen Brian Campbell'ın cevabını / cevabını + 1'leyin. benim değil! Önce çözümü sundu.


10

Diğer posterlerin söylediği gibi, SQLite bu sözdizimini desteklemez. Ben bileşik ınsert'ler SQL standardının parçası olup olmadığını bilmiyorum, ama benim deneyim onlar konum değil birçok üründe uyguladı.

Bir kenara, açık bir işlemde birden fazla INSERT kaydırırsanız, SQLite INSERT performansının önemli ölçüde arttığını bilmelisiniz.


10

Evet, sql bunu yapabilir, ancak farklı bir sözdizimi ile. Bu arada sqlite belgeleri oldukça iyi. Ayrıca , birkaç satır eklemenin tek yolunun, eklenecek verilerin kaynağı olarak bir select deyimi kullanmak olduğunu söyleyecektir .


9

Sqlite3 bunu SELECT dışında doğrudan SQL'de yapamaz ve SELECT ifadelerin bir "satırını" döndürebilirken, sahte bir sütun döndürmesini sağlamanın bir yolunu bilmiyorum.

Ancak, CLI bunu yapabilir:

.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> 

CLI kullanmak yerine INSERT çevresine bir döngü koyarsanız .import komutunu INSERT hızı için sqlite SSS bölümündeki önerilere uyduğunuzdan emin olun:

Varsayılan olarak, her INSERT ifadesi kendi işlemidir. Ancak birden çok INSERT deyimini BEGIN ... COMMIT ile çevrelerseniz, tüm ekler tek bir işlem halinde gruplanır. İşlemin yürütülmesi için gereken süre, ekteki tüm ekleme deyimleri üzerinden amortismana tabi tutulur ve böylece ekleme başına ifade süresi büyük ölçüde azaltılır.

Başka bir seçenek PRAGMA senkronize = KAPALI çalıştırmaktır. Bu komut, SQLite'nin disk yüzeyine ulaşmak için verileri beklememesine neden olur ve bu da yazma işlemlerinin çok daha hızlı görünmesini sağlar. Ancak bir işlemin ortasında güç kaybederseniz, veritabanı dosyanız bozulabilir.


SQLite .importkomutunun kaynak koduna bakarsanız , giriş dosyasından (veya tty) bir satırı ve ardından bu satır için bir INSERT ifadesini okuyarak bu sadece bir döngüdür. Ne yazık ki verimliliği önemli ölçüde iyileştirmedi.
Bill Karwin

8

Alex doğrudur: "select ... union" ifadesi bazı kullanıcılar için çok önemli olan sıralamayı kaybeder. Belirli bir siparişe eklediğinizde bile, sqlite bazı şeyleri değiştirir, bu nedenle ekleme sırası önemliyse işlemleri kullanmayı tercih edin.

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

fearless_fool'un eski sürümler için harika bir cevabı var. Listedeki tüm sütunlara sahip olduğunuzdan emin olmanız gerektiğini eklemek istedim. Dolayısıyla, 3 sütununuz varsa, seçmenin 3 sütun üzerinde etkili olduğundan emin olmanız gerekir.

Örnek: 3 sütunum var, ancak yalnızca 2 sütun değerinde veri eklemek istiyorum. İlk sütunu umursamadığımı varsayalım çünkü bu standart bir tamsayı kimliği. Aşağıdakileri yapabilirdim ...

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'

Not: "select ... union" ifadesinin sıralamayı kaybedeceğini unutmayın. (AG1'den)


7
INSERT INTO TABLE_NAME 
            (DATA1, 
             DATA2) 
VALUES      (VAL1, 
             VAL2), 
            (VAL1, 
             VAL2), 
            (VAL1, 
             VAL2), 
            (VAL1, 
             VAL2), 
            (VAL1, 
             VAL2), 
            (VAL1, 
             VAL2), 
            (VAL1, 
             VAL2), 
            (VAL1, 
             VAL2); 

6

Yapamazsın ama hiçbir şeyi özlediğini sanmıyorum.

Sqlite'ı her zaman işlemde olarak çağırdığınız için, 1 insert deyimi veya 100 insert deyimi yürütmeniz neredeyse hiç önemli değildir. Ancak, taahhüt çok zaman alır, bu nedenle bu 100 eki bir işleme koyun.

Sqlite parametreli sorgular (çok daha az ayrıştırma gerekli) kullandığınızda çok daha hızlı yani ben böyle büyük ifadeler bitiştirmek olmaz:

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

Her birleştirilmiş ifade farklı olduğu için tekrar tekrar ayrıştırılmaları gerekir.


6

mysql lite'de birden fazla değer ekleyemezsiniz, ancak bağlantıyı yalnızca bir kez açıp ardından tüm eklemeleri yapıp bağlantıyı kapatarak zaman kazanabilirsiniz. Çok zaman kazandırır


5

İşlemi kullanmayla ilgili sorun, tabloyu okumak için de kilitlemenizdir. Eklenecek çok fazla veriniz varsa ve verilerinize erişmeniz gerekiyorsa, bir önizleme veya benzeri bir şey için, bu şekilde iyi çalışmaz.

Diğer çözümle ilgili sorun, ekleme sırasını kaybetmenizdir

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

Sqlite veri a, b, c, d depolamak olacak ...


5

3.7.11 sürümünden itibaren SQLite çoklu satır ekleme özelliğini desteklemektedir. Richard Hipp şöyle diyor:

3.6.13 kullanıyorum

Ben böyle komut:

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

Bir seferde 50 kayıt eklendiğinde yalnızca bir saniye veya daha kısa sürer.

Bir seferde birden çok satır eklemek için sqlite kullanmak doğrudur. @Andy tarafından yazdı.

teşekkürler Andy +1


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


2

Aşağıdaki gibi bir sorgu var, ancak ODBC sürücüsü ile SQLite "," ile bir hata var diyor. HTA'da (Html ​​Uygulaması) vbscript çalıştırıyorum.

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

Sqlite 3.7.2 üzerinde:

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

ve bunun gibi


2

Sorguyu dinamik hale getirebiliyorum. Bu benim masam:

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

ve tüm verileri a yoluyla alıyorum JSON, bu yüzden her şeyi bir aldıktan sonra NSArraybunu takip ettim:

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

Ve son olarak çıktı sorgusu şudur:

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

hangi de kodu ile iyi çalışıyor ve başarıyla SQLite her şeyi kaydetmek mümkün.

Bundan önce UNIONsorgu şeyler dinamik yaptı ama bazı sözdizimi hatası vermeye başladı. Her neyse, bu benim için iyi çalışıyor.


2

Kimsenin hazırlanmış ifadelerden bahsetmediğine şaşırdım . SQL'i başka bir dilde değil, tek başına kullanmıyorsanız, o zaman bir işleme sarılmış hazırlanmış ifadelerin birden çok satır eklemenin en etkili yolu olacağını düşünürdüm.


1
Hazırlanan ifadeler her zaman iyi bir fikirdir, ancak OP'nin sorduğu soru ile hiç ilgili değildir. Bir ifadeye birden çok veri eklemek için temel sözdiziminin ne olduğunu soruyor.
Lakey


-1

Eğer bash kabuğu kullanıyorsanız bunu kullanabilirsiniz:

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

Veya sqlite CLI'deyseniz, bunu yapmanız gerekir:

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;

O nasıl çalışır? Eğer tabloyu kullanırsa tab:

id int
------
1
2

sonra select a.id, b.id from tab a, tab bgeri döner

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

ve bunun gibi. İlk yürütmeden sonra 2 satır, ardından 2 ^ 3 = 8 ekleriz. (üç çünkü var tab a, tab b, tab c)

İkinci yürütmeden sonra ek (2+8)^3=1000satırlar ekliyoruz

Öğleden sonra max(1000^3, 5e5)=500000sıraları yerleştiririz ...

Bu benim için bilinen en hızlı yöntemdir SQLite veritabanı doldurma.


2
Yararlı veriler eklemek istiyorsanız bu çalışmaz .
CL.

@CL. bu doğru değil. istediğiniz zaman rastgele tarihler ve kimliklerle karıştırabilirsiniz.
test30
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.