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

470

В MySQL вы можете вставить несколько строк следующим образом:

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

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

  • 22
    Не дурак, так как этот вопрос касается конкретно SQLite, в отличие от SQL в целом (хотя некоторые ответы на этот вопрос полезны для этого).
  • 4
    На массовых вставках: stackoverflow.com/questions/1711631/…
Показать ещё 3 комментария
Теги:
syntax

24 ответа

524
Лучший ответ

Обновление

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

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

Если бы у меня были привилегии, я бы bump andy reply: вы можете вставлять несколько строк в 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. Тем не менее, как указывает Хайме Кук, это не ясно, что это какая-то более быстрая упаковка 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, так как он более точно соответствует семантике исходного сообщения.

при закрытии

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

  • 100
    В качестве дальнейшего примечания, кажется, что sqlite поддерживает только до 500 таких объединений для каждого запроса, поэтому, если вы пытаетесь добавить больше данных, чем вам, вам нужно разбить их на 500 блоков элементов ( sqlite.org/limits.html )
  • 0
    Я не думаю, что это так сильно повышает производительность. Транзакции SQLite ОЧЕНЬ быстрые со вставками.
Показать ещё 13 комментариев
515

Да, это возможно, но не с обычными значениями вставки, разделенными запятыми.

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

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

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

  • 34
    пожалуйста, используйте UNION ALL не UNION . За исключением случаев, когда вы хотите удалить дубликаты.
  • 1
    Здорово. Это должно быть более эффективно, чем вызывать драйвер SQLite3 из моего кода для каждой вставки, верно?
Показать ещё 1 комментарий
229

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

Изображение 1117

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

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

  • 3
    Я бы сказал, что диаграмма допускает несколько строк, так как после VALUES есть замкнутый цикл с запятой вне скобок.
  • 0
    @JohannesGerer Они обновили это изображение с тех пор, как я его встроил. Вы можете увидеть диаграмму в то время, когда я встроил ее в интернет-архив . Фактически, всего два месяца назад они добавили поддержку нескольких строк в вставке и всего два дня назад выпустили версию с этим изменением. Я обновлю свой ответ соответственно.
Показать ещё 7 комментариев
47

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

BEGIN TRANSACTION;
INSERT INTO table VALUES (1,1,1,1);
INSERT INTO table VALUES (2,2,2,2);
...
COMMIT;
  • 1
    но это не работает в коде, в то время как он работает непосредственно в диспетчере SQLite. В коде он вставляет только 1-й ряд :(
  • 3
    Я использую этот стиль вставки в моем коде, и он отлично работает. Вам нужно только убедиться, что вы отправляете ВСЕ SQL одновременно. Для меня это было огромным увеличением скорости, но мне любопытно, будет ли принятый ответ быстрее или медленнее, чем этот?
Показать ещё 2 комментария
37

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

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

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

Начиная с версии 3.7.11 SQLite поддерживает multi-row-insert. Ричард Хипп:

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

  • 0
    Там нет никакого преимущества в производительности, так или иначе. - Не могли бы вы сказать мне, где вы видели это замечание? Я не мог найти это нигде.
  • 3
    Прямо здесь
11

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

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

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

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

10

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

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

10

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

8

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> 

Если вы наложили цикл на INSERT, а не на команду CLI .import, то обязательно следуйте советам в часто задаваемом FAQ sqlite для скорости INSERT:

По умолчанию каждый оператор INSERT его собственная сделка. Но если ты объединить несколько инструкций INSERT с BEGIN... COMMIT, тогда все вставки сгруппированы в один сделка. Время, необходимое для фиксации транзакция амортизируется по всем прилагаемые вставки и так далее время для инструкции вставки значительно сокращается.

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

  • 0
    Если вы посмотрите на исходный код команды SQLite .import , это просто цикл, считывающий строку из входного файла (или tty), а затем оператор INSERT для этой строки. К сожалению, не значительно улучшена эффективность.
  • 0
    Digital Ross, если вы помещаете большое количество операторов INSERT в одну транзакцию, то хотите поместить какую-то команду «break» в обработчик ошибок, чтобы в случае сбоя одного из операторов INSERT он не останавливал цикл ?
7

fearless_fool имеет отличный ответ для более старых версий. Я просто хотел добавить, что вам нужно убедиться, что все столбцы перечислены. Итак, если у вас есть 3 столбца, вам нужно убедиться, что select действует на 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... union" потеряет порядок. (Из AG1)

7

Алекс прав: оператор "select... union" потеряет порядок, который очень важен для некоторых пользователей. Даже когда вы вставляете в определенном порядке, 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
6
INSERT INTO TABLE_NAME 
            (DATA1, 
             DATA2) 
VALUES      (VAL1, 
             VAL2), 
            (VAL1, 
             VAL2), 
            (VAL1, 
             VAL2), 
            (VAL1, 
             VAL2), 
            (VAL1, 
             VAL2), 
            (VAL1, 
             VAL2), 
            (VAL1, 
             VAL2), 
            (VAL1, 
             VAL2); 
6

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

6

Ты не можешь, но я не думаю, что ты что-то пропускаешь.

Поскольку вы вызываете sqlite всегда в процессе, почти не важно, выполняете ли вы 1 инструкцию insert или 100 операторов insert. Однако фиксация занимает много времени, поэтому ставьте эти 100 вставок внутри транзакции.

Sqlite намного быстрее, когда вы используете параметризованные запросы (гораздо меньше требуется синтаксический анализ), поэтому я бы не стал конкатенацией больших операторов вроде этого:

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

Их нужно разбирать снова и снова, потому что каждое конкатенированное утверждение отличается.

5

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

Я использую 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 написал.

спасибо Andy +1

5

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

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

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

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

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

Я могу сделать запрос динамическим. Это моя таблица:

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 материал запроса динамический, но это начало давать некоторую синтаксическую ошибку. В любом случае, это работает хорошо для меня.

2

В sqlite 3.7.2:

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

и т.д.

2

У меня есть запрос, как показано ниже, но с драйвером 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())
2

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

Infact это не поддерживает, но Sqlite Browser работает (работает в Windows, OS X, Linux)

0

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

  • 1
    Подготовленные заявления всегда являются хорошей идеей, но никак не связаны с вопросом, который задает ФП. Он спрашивает, каков основной синтаксис для вставки нескольких данных в одном выражении.
0

вы можете использовать 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

  • 3
    InsertHelper устарел с API 17
-2

Если вы используете оболочку 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

Aftern thrid вставляем строки max(1000^3, 5e5)=500000 и так далее...

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

  • 2
    Это не работает, если вы хотите вставить полезные данные.
  • 0
    @CL. это неправда. Вы можете смешать его со случайными датами и идентификаторами, как вы хотите.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню