Можно ли одновременно вставлять несколько строк в базу данных SQLite?

в MySQL вы можете вставить несколько строк, как это:

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

однако я получаю ошибку, когда пытаюсь сделать что-то вроде этого. Можно ли одновременно вставлять несколько строк в базу данных SQLite? Каков синтаксис для этого?

24 ответов


обновление

As BrianCampbell указывает здесь, SQLite 3.7.11 и выше теперь поддерживает более простой синтаксис исходного сообщения. Однако показанный подход по-прежнему подходит, если требуется максимальная совместимость между устаревшими базами данных.

оригинальный ответ

если бы у меня были привилегии, я бы bump Энди вы can вставьте несколько строк в SQLite, вам просто нужно другой синтаксис. Чтобы было совершенно ясно, пример Ops MySQL:

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

это можно переделать в SQLite как:

     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'

примечание о производительности

первоначально я использовал этот метод для эффективной загрузки больших наборов данных из Ruby on Rails. , как отмечает Хайме Кук, неясно, что это более быстрая упаковка individual INSERTs в рамках одной транзакции:

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

если эффективность ваша цель, вы должны попробовать это первым.

примечание по UNION vs UNION ALL

как прокомментировали несколько человек, если вы используете UNION ALL (как показано выше), все строки будут вставлены, поэтому в этом случае вы получите четыре строки data1, data2. Если вы опустите ALL, затем повторяющиеся строки будут устранены (и операция, предположительно, будет немного медленнее). Мы используем UNION ALL, так как он более точно соответствует семантике исходного сообщения.

in закрытие

С. П.: Пожалуйста, +1 Энди, а не моя! Сначала он представил решение.


Да, это возможно, но не с обычными запятую вставить значения.

попробуйте это...

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

Да, это немного уродливо, но достаточно легко автоматизировать генерацию оператора из набора значений. Кроме того, похоже, вам нужно только объявить имена столбцов в первом выборе.


да, начиная с SQLite 3.7.11 это поддерживается в SQLite. От документация SQLite:

SQLite INSERT statement syntax

(когда этот ответ был написан, это был не поддерживается)

для совместимости со старыми версиями SQLite вы можете использовать трюк, предложенный Энди и fearless_fool используя UNION, но для 3.7.11 и более поздних версий более простой синтаксис, описанный здесь, должен быть предпочтительный.


Я написал код ruby для создания одной многорядной вставки 500 элементов из серии инструкций insert, которая была значительно быстрее, чем запуск отдельных вставок. Затем я попытался просто обернуть несколько вставок в одну транзакцию и обнаружил, что могу получить такую же скорость со значительно меньшим количеством кода.

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

по данным на этой странице не поддерживается:

  • 2007-12-03: многорядная вставка a.к. a. составная вставка не поддерживается.
  INSERT INTO table (col1, col2) VALUES 
      ('row1col1', 'row1col2'), ('row2col1', 'row2col2'), ...

На самом деле, согласно стандарту SQL92, выражение значений должно быть в состоянии стоять на себе. Например, следующая таблица должна возвращать таблицу из одного столбца с тремя строками:VALUES 'john', 'mary', 'paul';

начиная с версии 3.7.11 SQLite тут поддержка многорядные-вставить. Ричард Хипп комментарии:

" новая многозначная вставка-это просто синтаксический suger (sic) для соединения вставлять. Нет никакого преимущества в производительности так или иначе."


начиная с версии 2012-03-20( 3.7.11), SQLite поддерживает следующий синтаксис вставки:

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

прочитайте документацию:http://www.sqlite.org/lang_insert.html

PS: пожалуйста +1 к ответу/ответу Брайана Кэмпбелла. не моя! Сначала он представил решение.


Как говорили другие плакаты, SQLite не поддерживает этот синтаксис. Я не знаю, являются ли составные вставки частью стандарта SQL, но по моему опыту они не реализована во многих продуктах.

в стороне, вы должны знать, что производительность вставки в SQLite значительно улучшается, если вы обернете несколько вставок в явной транзакции.


да, sql может это сделать, но с другим синтаксисом. The документация sqlite довольно неплохо, кстати. Это также скажет вам что единственный способ, чтобы вставить несколько строк используйте инструкцию select в качестве источника вставляемых данных.


Sqlite3 не может сделать это непосредственно в SQL, кроме как через SELECT, и, хотя SELECT может возвращать "строку" выражений, я не знаю, как заставить его вернуть фальшивый столбец.

однако CLI может это сделать:

.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 .import команда, затем обязательно следуйте советам в SQLite FAQ для скорости вставки:

по умолчанию каждый оператор INSERT собственные сделки. Но если вы окружить несколько инструкций INSERT с начала...Совершите тогда все вставки группируются в один торговая операция. Время, необходимое для совершения сделки амортизируется за все прилагаемые инструкции insert и так далее время на инструкцию insert значительно сократить.

другой вариант-запустить PRAGMA синхронно=выкл. Эта команда причина SQLite не ждать данных для достигает поверхности диска, которая сделать операции записи гораздо быстрее. Но если ты потеряешь власть ... середина сделки, ваша файл базы данных может быть поврежден.


Alex правильно: "выбрать ... заявление "Союз" потеряет заказ, что очень важно для некоторых пользователей. Даже когда вы вставляете в определенном порядке, sqlite изменяет вещи, поэтому предпочитает использовать транзакции, если порядок вставки важен.

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

fearless_fool имеет отличный ответ для более старых версий. Я просто хотел добавить, что вам нужно убедиться, что у вас есть все перечисленные столбцы. Поэтому, если у вас есть 3 столбца, вам нужно убедиться, что выберите действия на 3 столбцах.

пример:у меня есть 3 столбца, но я хочу вставить только 2 столбца данных. Предположим, меня не волнует первый столбец, потому что это стандартный целочисленный идентификатор. Я мог бы сделать следующее...

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'

Примечание: помните "select ... Союз" заявление потерять заказ. (Из AG1)


в mysql lite вы не можете вставить несколько значений, но вы можете сэкономить время, открыв соединение только один раз, а затем выполнив все вставки, а затем закрыв соединение. Это экономит много времени


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

проблема с использованием транзакции заключается в том, что вы блокируете таблицу также для чтения. Поэтому, если у вас действительно много данных для вставки, и вам нужен доступ к вашим данным, например, предварительный просмотр или так, этот способ не работает хорошо.

проблема с другим решением заключается в том, что вы теряете порядок вставки

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

в sqlite данные будут хранить a,b,c, d...


начиная с версии 3.7.11 SQLite поддерживает многорядную вставку. Ричард Комментарии Хипп:

Я использую 3.6.13

я командую так:

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

С 50 записями, вставленными одновременно, это занимает всего секунду или меньше.

это правда, что использование sqlite для вставки нескольких строк за раз очень возможно. Автор @Andy написал.

спасибо Энди +1


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

Если вы используете SQLite менеджер плагин firefox, он поддерживает массовые вставки из INSERT SQL-операторы.

Infact он не поддерживает это, но SQLite В Браузере делает (работает на Windows, OS X, Linux)


У меня есть запрос, как показано ниже, но с драйвером ODBC SQLite имеет ошибку С", " он говорит. Я запускаю vbscript в HTA (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())

на sqlite 3.7.2:

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

и так далее


Я могу сделать запрос динамически. Вот мой стол:--7-->

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

и я получаю все данные через JSON, поэтому после получения всего внутри NSArray я продолжил:

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

и, наконец, выходной запрос таков:

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

который также хорошо работает через код, и я могу сохранить все в SQLite успешно.

до этого я составила UNION динамический запрос, но это начало давать некоторые ошибки синтаксиса. В любом случае, для меня все идет хорошо.


Я удивлен, что никто не упомянул подготовленные заявления. Если вы не используете SQL самостоятельно, а не на каком-либо другом языке, я бы подумал, что подготовленные заявления завернут в сделки будет наиболее эффективным способом вставки нескольких строк.


вы можете использовать InsertHelper, это легко и быстро

документация: http://developer.android.com/reference/android/database/DatabaseUtils.InsertHelper.html

учебник: http://www.outofwhatbox.com/blog/2010/12/android-using-databaseutils-inserthelper-for-faster-insertions-into-sqlite-database/

изменить: InsertHelper устарел с уровня API 17


если вы используете оболочку bash, вы можете использовать это:

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

или если вы находитесь в SQLite CLI, то вам нужно сделать это:

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;

как это работает? Он использует это, если таблица tab:

id int
------
1
2

затем select a.id, b.id from tab a, tab b возвращает

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

и так далее. После первого выполнения вставляем 2 строки, затем 2^3=8. (три, потому что у нас есть tab a, tab b, tab c)

после второго выполнения вставляем дополнительно (2+8)^3=1000 строки

вечернего чаепития. третье мы вставляем о max(1000^3, 5e5)=500000 строк и так далее...

это самый быстрый известный мне способ заполнения базы данных SQLite.