是否有可能在SQLite数据库中一次插入多行?
在MySQL中,你可以像这样插入多行:
INSERT INTO 'tablename' ('column1', 'column2') VALUES ('data1', 'data2'), ('data1', 'data2'), ('data1', 'data2'), ('data1', 'data2');
然而,当我尝试做这样的事情时,我得到一个错误。 是否有可能在SQLite数据库中一次插入多行? 这是什么语法?
更新
正如BrianCampbell指出的那样 , SQLite 3.7.11及更高版本现在支持原始文章的更简单的语法 。 但是,如果您希望在传统数据库之间达到最大的兼容性,则所示方法仍然适用
原来的答案
如果我有权限,我会碰到andy的回答 :你可以在SQLite中插入多行,你只需要不同的语法 。 为了使它完全清楚,OP的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;
如果效率是你的目标,你应该先尝试一下。
一个关于联盟vs联盟所有的说明
正如几个人所评论的,如果你使用UNION ALL
(如上所示),所有的行将被插入,所以在这种情况下,你会得到四行data1, data2
。 如果你省略了ALL
,那么重复的行将被消除(操作可能会慢一点)。 我们使用UNION ALL,因为它更接近原始post的语义。
在结束
PS:请+1 Andy的回复 ,不是我的! 他首先提出了解决scheme。
是的,这是可能的,但不是通常逗号分隔的插入值。
尝试这个…
insert into myTable (col1,col2) select aValue as col1,anotherValue as col2 union select moreValue,evenMoreValue union...
是的,这有点难看,但是很容易使一组值的生成自动化。 另外,看起来你只需要在第一个select中声明列名。
是的,从SQLite 3.7.11开始,这在SQLite中是受支持的。 从SQLite文档 :
(当这个答案是最初写的,这是不支持的)
为了与旧版本的SQLite兼容,你可以使用UNION
的andy和fearless_fool技巧,但是对于3.7.11和更高版本,这里描述的更简单的语法应该是优选的。
我写了一些ruby代码,从一系列插入语句中生成一个500元素的多行插入,比运行单个插入语句要快得多。 然后,我试图简单地将多个插入包装到一个事务中,发现我可以用相当less的代码获得相同的加速。
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 INTO table (col1, col2) VALUES ('row1col1', 'row1col2'), ('row2col1', 'row2col2'), ...
实际上,根据SQL92标准,一个VALUESexpression式应该能够自己站立起来。 例如,下面的代码应该返回一个包含三行的单列表:
VALUES 'john', 'mary', 'paul';
从版本3.7.11开始,SQLite支持多行插入 。 理查德·希普评论说:
“新的多值插入仅仅是复合插入的语法suic(sic),没有任何性能优势。”
正如其他海报所说,SQLite不支持这种语法。 我不知道复合插入是否是SQL标准的一部分,但根据我的经验,它们在许多产品中都没有实现。
另外,你应该知道,如果你在一个显式的事务中包装多个INSERT,SQLite中的INSERT性能会得到相当大的提高。
是的,sql可以做到这一点,但使用不同的语法。 顺便说一句, sqlite文档是相当不错的。 它还会告诉你 ,插入多行的唯一方法是使用select语句作为要插入的数据的来源。
sqlite3不能直接在SQL中,除了通过一个SELECT,而SELECT可以返回expression式的“行”,我知道没有办法让它返回一个虚假的列。
但是,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速度的build议:
默认情况下,每个INSERT语句都是它自己的事务。 但是,如果使用BEGIN … COMMIT包围多个INSERT语句,则所有插入操作都会分组到一个事务中。 提交事务所需的时间将在所有随附的插入语句之间进行摊销,因此每个插入语句的时间大大减less。
另一个选项是运行PRAGMA synchronous = OFF。 这个命令将导致SQLite不等待数据到达磁盘表面,这将使写操作看起来更快。 但是,如果在事务处理过程中失去了权力,那么数据库文件可能会损坏。
从版本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。 不是我的! 他首先提出了解决scheme。
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列,你需要确保select3列的行为。
例如:我有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”语句会失去sorting。 (来自AG1)
你不能,但我不认为你会错过任何东西。
因为你总是在调用sqlite,所以执行1个insert语句或100个insert语句在性能上几乎没有关系。 然而提交需要很多时间,所以把这100个插入一个事务中。
当你使用参数化查询时,Sqlite会快得多(不需要parsing),所以我不会像这样连接大的语句:
insert into mytable (col1, col2) select 'a','b' union select 'c','d' union ...
他们需要一次又一次的parsing,因为每个连接的语句是不同的。
在MySQL精简版中,您不能插入多个值,但只需打开一次连接,然后执行所有插入操作,然后closures连接即可节省时间。 它节省了很多时间
INSERT INTO TABLE_NAME (DATA1, DATA2) VALUES (VAL1, VAL2), (VAL1, VAL2), (VAL1, VAL2), (VAL1, VAL2), (VAL1, VAL2), (VAL1, VAL2), (VAL1, VAL2), (VAL1, VAL2);
使用事务的问题是您locking表也阅读。 所以如果你有太多的数据要插入,你需要访问你的数据,例如预览等,这种方式是行不通的。
另一个解决scheme的问题是你失去了插入的顺序
insert into mytable (col) select 'c' union select 'd' union select 'a' union select 'b';
在sqlite的数据将被存储在一个,B,C,D …
从版本3.7.11开始,SQLite支持多行插入。 理查德·希普评论说:
我正在使用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条logging,只需要一秒钟或更less的时间。
这是真的使用sqlite一次插入多行是非常可能的。 @Andy写道。
感谢安迪+1
INSERT INTO tabela(coluna1,coluna2) SELECT 'texto','outro' UNION ALL SELECT 'mais texto','novo texto';
如果你使用Sqlitepipe理器的 firefox插件,它支持来自 INSERT
SQL语句的批量插入。
事实上,它不支持这个,但Sqlite浏览器 (适用于Windows,OS X,Linux)
我有一个像下面的查询,但与ODBC驱动程序SQLite有一个“,”它说错误。 我在HTA(Html应用程序)中运行VBScript。
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())
在sqlite 3.7.2上:
INSERT INTO table_name (column1, column2) SELECT 'value1', 'value1' UNION SELECT 'value2', 'value2' UNION SELECT 'value3', 'value3'
等等
我能够使查询dynamic。 这是我的桌子:
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
查询的东西dynamic,但开始给一些语法错误。 无论如何,这对我来说运行良好。
你可以使用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
我很惊讶,没有人提到准备好的发言 。 除非你自己使用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;
它是如何工作的? 它使用,如果表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数据库的最快速的方法。