Можно ли вставлять несколько строк одновременно в базу данных SQLite? - PullRequest
518 голосов
/ 23 октября 2009

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

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

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

Ответы [ 24 ]

585 голосов
/ 16 февраля 2011

обновление

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

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

Если бы у меня были привилегии, я бы поднял ответ andy : Вы можете вставить несколько строк в 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 против UNION ALL

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

при закрытии

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

546 голосов
/ 14 ноября 2009

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

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

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

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

230 голосов
/ 23 октября 2009

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

SQLite INSERT statement syntax

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

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

56 голосов
/ 06 марта 2011

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

BEGIN TRANSACTION;
INSERT INTO table VALUES (1,1,1,1);
INSERT INTO table VALUES (2,2,2,2);
...
COMMIT;
37 голосов
/ 23 октября 2009

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

  • 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 поддерживает вставка нескольких строк . Ричард Хипп комментирует:

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

14 голосов
/ 16 мая 2013

Начиная с версии 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 голосов
/ 14 ноября 2009

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

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

10 голосов
/ 23 октября 2009

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

8 голосов
/ 19 июня 2012

Алекс прав: оператор "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
8 голосов
/ 23 октября 2009

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

По умолчанию каждый оператор INSERT его собственная сделка. Но если ты окружить несколько операторов INSERT с НАЧАТЬ ... COMMIT тогда все вставки сгруппированы в единый сделка. Время, необходимое для совершения сделка амортизируется по всем вложенные операторы вставки и так время на вставку значительно уменьшено.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...