是否可以在SQLite数据库中一次插入多行?

在MySQL中,你可以像这样插入多行:

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

然而,当我尝试这样做时,我得到了一个错误。是否可以在SQLite数据库中一次插入多行?这样做的语法是什么?

464952 次浏览

是的,sql可以做到这一点,但是使用不同的语法。顺便说一下,sqlite文档非常好。插入几行的唯一方法是将使用选择语句作为要插入的数据的源。

是的,从SQLite 3.7.11开始,SQLite支持这个功能。SQLite文档:

SQLite INSERT语句语法

(当这个答案最初写的时候,这是不支持的)

为了兼容旧版本的SQLite,您可以使用安迪fearless_fool所建议的技巧,使用UNION,但对于3.7.11及以后版本,这里描述的更简单的语法应该是首选。

根据这个页面,不支持:

  • 2007-12-03:不支持多行插入,也就是复合插入。
  INSERT INTO table (col1, col2) VALUES
('row1col1', 'row1col2'), ('row2col1', 'row2col2'), ...

实际上,根据SQL92标准,VALUES表达式应该能够独立存在。例如,下面的代码应该返回一个三行单列表:VALUES 'john', 'mary', 'paul';

从3.7.11版本开始,SQLite 支持multi-row-insert。Richard Hipp评论道:

"新的多值插入仅仅是该化合物的语法糖(sic) 插入。这两种方法都没有性能优势。" < / p >

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然后所有 insert被分组为单个 事务。承诺所需的时间 该事务被全部摊销 所附的插入语句等等 每个插入语句的时间为 大大降低。< / p > 另一种选择是运行PRAGMA 同步=。这个命令将 导致SQLite不等待数据 到达磁盘表面,这将 使写操作看起来是 快得多。但是如果你断电了 在交易过程中,你的

.数据库文件可能会损坏

是的,这是可能的,但不是通常的逗号分隔的插入值。

试试这个…

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

是的,这有点丑陋,但是从一组值自动生成语句足够简单。而且,似乎只需要在第一个选择中声明列名。

正如其他人所说,SQLite不支持这种语法。我不知道复合insert是否是SQL标准的一部分,但根据我的经验,它们在许多产品中是实现的。

顺便说一句,您应该意识到,如果在显式事务中包装多个INSERT, SQLite中的INSERT性能将大大提高。

你不能,但我不认为你错过了什么。

因为sqlite总是在进程中调用,所以执行1条插入语句还是100条插入语句对性能几乎没有影响。然而,提交需要花费很多时间,所以将这100个插入放在事务中。

当你使用参数化查询时,Sqlite要快得多(需要的解析要少得多),所以我不会像这样串联大语句:

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

它们需要一遍又一遍地解析,因为每个连接的语句都是不同的。

如果你使用Sqlite管理器 firefox插件,它支持从INSERT SQL语句批量插入。

事实上,它不支持这一点,但Sqlite浏览器做(适用于Windows, OS X, Linux)

在mysql lite中不能插入多个值, 但是您可以通过只打开一次连接,然后执行所有插入,然后关闭连接来节省时间。 它节省了很多时间

更新

布莱恩·坎贝尔指出SQLite 3.7.11及以上版本现在支持原始文章中更简单的语法。但是,如果您希望在遗留数据库之间实现最大的兼容性,则所示的方法仍然是合适的。

原来的答案

如果我有特权,我会撞河流的回复:你可以插入多行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,因为它更接近原始帖子的语义。

在关闭

附注:请+1 河流的回复,因为它首先提出了解决方案。

我编写了一些ruby代码,从一系列插入语句中生成一个500个元素的多行插入,这比运行单个插入快得多。然后我尝试简单地将多个插入打包到一个事务中,发现我可以用更少的代码获得同样的速度。

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

使用事务的问题是,您还锁定了用于读取的表。所以,如果你有很多数据要插入,你需要访问你的数据,例如预览之类的,这种方式就不太适用了。

另一个解决方案的问题是,您失去了插入的顺序

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

在sqlite中,数据将被存储为a,b,c,d…

INSERT INTO tabela(coluna1,coluna2)
SELECT 'texto','outro'
UNION ALL
SELECT 'mais texto','novo texto';
从3.7.11版本开始,SQLite支持多行插入。理查德。 Hipp评论:< / p >

我使用的是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

Alex是正确的:“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
INSERT INTO TABLE_NAME
(DATA1, DATA2)
VALUES      (VAL1, VAL2),
(VAL1, VAL2),
(VAL1, VAL2),
(VAL1, VAL2),
(VAL1, VAL2),
(VAL1, VAL2),
(VAL1, VAL2),
(VAL1, VAL2);

我有一个如下的查询,但与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())

Fearless_fool对于旧版本有一个很好的答案。我只是想补充一下,你需要确保你列出了所有的列。如果你有3列,你需要确保select作用在3列上。

示例:我有3列,但我只想插入2列的数据。假设我不关心第一列因为它是一个标准整数id。我可以这样做……

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)

在sqlite 3.7.2上:

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

等等

我能够使查询动态。这是我的桌子:

# EYZ0

我通过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查询动态的东西,但开始给一些语法错误。不管怎样,这对我来说很好。

从版本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:请给Brian Campbell的回复+1。不是我的!他首先提出了解决方案。

你可以使用InsertHelper,它简单快捷

< p >文档: # EYZ0 < / p > < p >教程: # EYZ0 < / p > < p >编辑: InsertHelper在API级别17

时已弃用

我很惊讶没有人提到准备好的语句。除非您单独使用SQL,而不是在任何其他语言中使用,否则我认为将准备好的语句包装在事务中是插入多行最有效的方法。

如果你正在使用bash shell,你可以使用这个:

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;

它是如何工作的? 它使用if表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行等等…

# EYZ0

简单。自我解释。

在版本3.36.0 11/20/21上进行测试。

CREATE TEMP TABLE x (col1 TEXT, col2 TEXT, col3 TEXT);


INSERT INTO x
VALUES
('xx','yy','cc'),
('xx','yy','cc'),
('xx','yy','cc'),
('xx','yy','cc'),
('xx','yy','cc'),
('xx','yy','cc');


SELECT * FROM x;

输出:

col1|col2|col3|
----+----+----+
xx  |yy  |cc  |
xx  |yy  |cc  |
xx  |yy  |cc  |
xx  |yy  |cc  |
xx  |yy  |cc  |
xx  |yy  |cc  |

版本检查:

SELECT sqlite_version();

输出:

sqlite_version()|
----------------+
3.36.0          |

有人可能会说-所有的"联盟. .“答案已经过时了;尽管如此,它们还是非常有用的。有时候我们都坐在自己的办公桌上,“过去的爆炸”。15年前的钞票拯救了我们。