Подтвердить что ты не робот

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

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

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

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

4b9b3361

Ответ 1

Обновление

Как 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, а не мой! Сначала он представил решение.

Ответ 2

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

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

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

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

Ответ 3

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

SQLite INSERT statement syntax

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

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

Ответ 4

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

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

Ответ 5

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

  • 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) для соединения вставить. Преимущество производительности не существует так или иначе".

Ответ 6

Начиная с версии 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 к Брайану Кэмпбеллу ответ/ответ. не мой! Сначала он представил решение.

Ответ 7

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

Ответ 8

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

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

Ответ 9

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 не ждать данных достигнуть поверхности диска, сделать операции записи кажутся намного быстрее. Но если вы потеряете власть в в середине транзакции, файл базы данных может испортиться.

Ответ 10

Алекс прав: оператор "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

Ответ 11

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)

Ответ 12

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

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

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

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

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

Ответ 13

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

Ответ 14

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

Ответ 15

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

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

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

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

Ответ 16

Начиная с версии 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

Ответ 17

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

Ответ 18

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

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

Ответ 19

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

Ответ 20

В sqlite 3.7.2:

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

и т.д.

Ответ 21

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

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

Ответ 23

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

Ответ 24

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