在MySQL中,您可以像这样插入多行:
INSERT INTO 'tablename' ('column1', 'column2') VALUES
('data1', 'data2'),
('data1', 'data2'),
('data1', 'data2'),
('data1', 'data2');
但是,尝试执行此类操作时出现错误。是否可以一次在SQLite数据库中插入多行?这样做的语法是什么?
在MySQL中,您可以像这样插入多行:
INSERT INTO 'tablename' ('column1', 'column2') VALUES
('data1', 'data2'),
('data1', 'data2'),
('data1', 'data2'),
('data1', 'data2');
但是,尝试执行此类操作时出现错误。是否可以一次在SQLite数据库中插入多行?这样做的语法是什么?
Answers:
正如BrianCampbell在此处指出的那样,SQLite 3.7.11及更高版本现在支持原始文章的更简单语法。但是,如果您希望在旧数据库之间实现最大兼容性,则所示的方法仍然适用。
如果有特权,我会激怒River的回答:您可以在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有效地加载大型数据集。 但是,正如Jaime Cook所指出的那样,尚不清楚这是否可以更快地将INSERTs
单个交易包装到单个交易中:
BEGIN TRANSACTION;
INSERT INTO 'tablename' table VALUES ('data1', 'data2');
INSERT INTO 'tablename' table VALUES ('data3', 'data4');
...
COMMIT;
如果效率是您的目标,则应首先尝试这样做。
正如几个人评论的那样,如果您使用UNION ALL
(如上所示),将插入所有行,因此,在这种情况下,您将获得4行data1, data2
。如果您省略ALL
,则将消除重复的行(并且该操作可能会慢一些)。我们正在使用UNION ALL,因为它与原始帖子的语义更加匹配。
PS:请+1 River的回复,因为它首先提出了解决方案。
insert into t values (data),(data),(data)
还是begin transaction; insert into t values (data);insert into t values (data);insert into t values (data);Commit;
?
UNION ALL
以避免(或一些小的性能提升)。
sqlite3.sqlite_version
(应该是3.7.x或3.8.x),而不是sqlite3.version
(仅仅是python模块的版本)。
是的,可以,但是不能使用通常的逗号分隔的插入值。
尝试这个...
insert into myTable (col1,col2)
select aValue as col1,anotherValue as col2
union select moreValue,evenMoreValue
union...
是的,这有点难看,但很容易从一组值自动生成语句。同样,看来您只需要在第一个选择中声明列名称。
UNION ALL
不要使用UNION
。除非您要删除重复项。
是的,从SQLite 3.7.11开始,SQLite 支持此功能。从SQLite文档中:
(最初写此答案时,不支持此答案)
为了与旧版本的SQLite的兼容性,可以使用所建议的伎俩安迪和fearless_fool使用UNION
,但对于3.7.11,后来在这里所描述的简单的语法应该是首选。
VALUES
。
VALUES (...), (...)
):(
我编写了一些ruby代码,从一系列插入语句生成一个500元素的多行插入,这比运行单个插入要快得多。然后,我尝试将多个插入内容包装到一个事务中,发现用更少的代码即可获得相同的速度。
BEGIN TRANSACTION;
INSERT INTO table VALUES (1,1,1,1);
INSERT INTO table VALUES (2,2,2,2);
...
COMMIT;
根据此页面,它不受支持:
- 2007-12-03:不支持多行INSERT aka复合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)。一种或另一种方式没有性能优势。”
从版本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
附言:请+1布莱恩·坎贝尔的回复/答案。不是我的!他首先提出了解决方案。
正如其他发布者所言,SQLite不支持此语法。我不知道复合INSERT是否属于SQL标准,但是根据我的经验,它们不是在许多产品中实现。
顺便说一句,您应该意识到,如果在一个显式事务中包装多个INSERT,则SQLite中的INSERT性能将得到显着提高。
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语句都是其自己的事务。但是,如果用BEGIN ... COMMIT包围多个INSERT语句,则所有插入都被分组为一个事务。提交事务所需的时间在所有随附的插入语句中摊销,因此每个插入语句的时间大大减少。
另一种选择是运行PRAGMA同步= OFF。此命令将导致SQLite不等待数据到达磁盘表面,这将使写入操作显得更快。但是,如果您在事务处理过程中断电,则数据库文件可能会损坏。
.import
命令的源代码,那只是一个循环,从输入文件(或tty)中读取一行,然后从该行读取INSERT语句。不幸的是效率没有明显提高。
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
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 ... union”语句将失去顺序。(来自AG1)
INSERT INTO tabela(coluna1,coluna2)
SELECT 'texto','outro'
UNION ALL
SELECT 'mais texto','novo texto';
如果您使用Sqlite Manager firefox插件,则它支持从INSERT
SQL语句进行批量插入。
实际上,它不支持此功能,但是Sqlite Browser可以(在Windows,OS X,Linux上运行)
我能够使查询动态化。这是我的桌子:
CREATE TABLE "tblPlanner" ("probid" text,"userid" TEXT,"selectedtime" DATETIME,"plannerid" TEXT,"isLocal" BOOL,"applicationid" TEXT, "comment" TEXT, "subject" TEXT)
并且我通过获取所有数据JSON
,因此在将所有内容都放入a 之后,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/
编辑:从API级别17开始不推荐使用InsertHelper
如果您使用的是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
行,依此类推...
这是对我来说最快的填充SQLite数据库的方法。