Is it possible to insert multiple rows at a time in an SQLite database?
在MySQL中,您可以这样插入多行:
1 2 3 4 5 | INSERT INTO 'tablename' ('column1', 'column2') VALUES ('data1', 'data2'), ('data1', 'data2'), ('data1', 'data2'), ('data1', 'data2'); |
但是,当我尝试这样做时,我会得到一个错误。是否可以在一个sqlite数据库中一次插入多行?这样做的语法是什么?
更新
正如Briancampbell在这里指出的,sqlite 3.7.11及更高版本现在支持原始日志的简单语法。但是,如果您希望跨遗留数据库实现最大的兼容性,那么所显示的方法仍然适用。
原始答案如果我有特权,我会打断安迪的回答:您可以在sqlite中插入多行,您只需要不同的语法。为了非常清楚,ops mysql示例:
1 2 3 4 5 | INSERT INTO 'tablename' ('column1', 'column2') VALUES ('data1', 'data2'), ('data1', 'data2'), ('data1', 'data2'), ('data1', 'data2'); |
可以将其重新转换为sqlite,如下所示:
1 2 3 4 5 | 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' |
关于表演的说明
我最初使用这种技术来有效地从RubyonRails加载大型数据集。然而,正如Jaime Cook指出的,不清楚这是否能更快地将单个
1 2 3 4 5 | BEGIN TRANSACTION; INSERT INTO 'tablename' TABLE VALUES ('data1', 'data2'); INSERT INTO 'tablename' TABLE VALUES ('data3', 'data4'); ... COMMIT; |
如果效率是你的目标,你应该先试试这个。
关于"联合"与"联合所有人"的注释正如一些人所评论的,如果您使用
附言:请+1安迪的回复,不是我的!他先提出了解决办法。
是的,这是可能的,但不能用逗号分隔的插入值。
试试这个…
1 2 3 4 | INSERT INTO myTable (col1,col2) SELECT aValue AS col1,anotherValue AS col2 UNION SELECT moreValue,evenMoreValue UNION... |
是的,它有点难看,但很容易从一组值自动生成语句。此外,您似乎只需要在第一次选择中声明列名。
是的,从sqlite 3.7.11开始,它在sqlite中受支持。从sqlite文档中:
(最初编写此答案时,不支持此操作)
为了与旧版本的sqlite兼容,您可以使用安迪和无畏的傻瓜使用
我编写了一些Ruby代码,用一系列的insert语句生成一个500元素的多行insert,这比运行单个insert快得多。然后我尝试简单地将多个插入封装到一个事务中,发现我可以用更少的代码获得相同的速度。
1 2 3 4 5 | BEGIN TRANSACTION; INSERT INTO TABLE VALUES (1,1,1,1); INSERT INTO TABLE VALUES (2,2,2,2); ... COMMIT; |
根据此页面,不支持:
- 2007-12-03 : Multi-row INSERT a.k.a. compound INSERT not supported.
1 2 | INSERT INTO TABLE (col1, col2) VALUES ('row1col1', 'row1col2'), ('row2col1', 'row2col2'), ... |
Actually, according to the SQL92 standard, a VALUES expression should be able to stand on itself. For example, the following should return a one-column table with three rows:
VALUES 'john', 'mary', 'paul';
从3.7.11版开始,sqlite支持多行插入。Richard Hipp评论:
"The new multi-valued insert is merely syntactic suger (sic) for the compound
insert. There is no performance advantage one way or the other."
从版本2012-03-20(3.7.11)开始,sqlite支持以下插入语法:
1 2 3 4 5 | INSERT INTO 'tablename' ('column1', 'column2') VALUES ('data1', 'data2'), ('data3', 'data4'), ('data5', 'data6'), ('data7', 'data8'); |
阅读文档:http://www.sqlite.org/lang_insert.html
附言:请+1到布莱恩坎贝尔的答复/回答。不是我的!他先提出了解决办法。
正如其他海报所说,sqlite不支持这种语法。我不知道复合插入是否是SQL标准的一部分,但根据我的经验,它们并没有在许多产品中实现。
另外,您应该知道,如果在一个显式事务中包装多个插入,那么SQLite中的插入性能会大大提高。
是的,SQL可以这样做,但使用不同的语法。顺便说一下,sqlite文档非常好。它还将告诉您插入多行的唯一方法是使用select语句作为要插入的数据源。
除了通过select,sqlite3不能在SQL中直接执行此操作,尽管select可以返回表达式的"行",但我不知道如何使它返回虚假的列。
但是,CLI可以做到:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | .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> |
如果您确实围绕插入放置了一个循环,而不是使用cli
By default, each INSERT statement is
its own transaction. But if you
surround multiple INSERT statements
with BEGIN...COMMIT then all the
inserts are grouped into a single
transaction. The time needed to commit
the transaction is amortized over all
the enclosed insert statements and so
the time per insert statement is
greatly reduced.Another option is to run PRAGMA
synchronous=OFF. This command will
cause SQLite to not wait on data to
reach the disk surface, which will
make write operations appear to be
much faster. But if you lose power in
the middle of a transaction, your
database file might go corrupt.
亚历克斯是对的:"选择……union语句将丢失对某些用户非常重要的排序。即使以特定的顺序插入,如果插入顺序很重要,SQLite也会更改内容,因此更喜欢使用事务。
1 2 3 4 5 6 7 8 9 10 11 | 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 |
无畏的傻瓜对旧版本有很好的答案。我只是想补充一下,您需要确保列出了所有列。因此,如果有3列,则需要确保选择"对3列执行"。
示例:我有3列,但我只想插入值为2列的数据。假设我不关心第一列,因为它是一个标准的整数ID。我可以执行以下操作…
1 2 3 4 5 | 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' |
注意:记住"选择…"union"语句将丢失命令。(来自AG1)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | INSERT INTO TABLE_NAME (DATA1, DATA2) VALUES (VAL1, VAL2), (VAL1, VAL2), (VAL1, VAL2), (VAL1, VAL2), (VAL1, VAL2), (VAL1, VAL2), (VAL1, VAL2), (VAL1, VAL2); |
你不能,但我不认为你错过了什么。
因为您总是在进程中调用sqlite,所以无论是执行1个insert语句还是100个insert语句,在性能上都几乎没有关系。然而,提交需要很多时间,所以将这100个插入放到事务中。
当您使用参数化查询时,sqlite速度要快得多(需要的解析要少得多),因此我不会像下面这样连接大型语句:
1 2 3 4 5 | INSERT INTO mytable (col1, col2) SELECT 'a','b' UNION SELECT 'c','d' UNION ... |
它们需要一次又一次地被解析,因为每个连接的语句都是不同的。
在mysql lite中,不能插入多个值,但您可以通过只打开一次连接,然后执行所有插入,然后关闭连接来节省时间。它节省了很多时间
使用事务的问题是,您也为读取而锁定了表。因此,如果您有很多数据需要插入,并且需要访问您的数据,例如预览,那么这种方法不太管用。
另一个解决方案的问题是您丢失了插入的顺序
1 2 3 4 5 6 7 8 | INSERT INTO mytable (col) SELECT 'c' UNION SELECT 'd' UNION SELECT 'a' UNION SELECT 'b'; |
在sqlite中,数据将存储在a、b、c、d…
As of version 3.7.11 SQLite does support multi-row-insert. Richard
Hipp comments:
我用的是3.6.13
我命令如下:
1 2 | INSERT INTO xtable(f1,f2,f3) SELECT v1 AS f1, v2 AS f2, v3 AS f3 UNION SELECT nextV1+, nextV2+, nextV3+ |
一次插入50条记录,只需一秒钟或更短的时间。
使用sqlite一次插入多行是很有可能的。由安迪写道。
谢谢安迪+ 1
1 2 3 4 | INSERT INTO tabela(coluna1,coluna2) SELECT 'texto','outro' UNION ALL SELECT 'mais texto','novo texto'; |
如果您使用sqlite manager firefox插件,它支持从
事实上,它不支持这一点,但sqlite浏览器支持这一点(适用于Windows、OS X、Linux)
我有一个如下的查询,但是对于ODBC驱动程序,sqlite有一个错误,它说。我在HTA(HTML应用程序)中运行vbscript。
1 | 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上:
1 2 3 4 | INSERT INTO TABLE_NAME (column1, column2) SELECT 'value1', 'value1' UNION SELECT 'value2', 'value2' UNION SELECT 'value3', 'value3' |
等等
我能够使查询成为动态的。这是我的桌子:
我通过一个
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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]; |
最后,输出查询是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | INSERT INTO tblPlanner (plannerid, probid, userid, selectedtime, isLocal, applicationid, subject, comment) VALUES ('pl1176428260', '', 'US32552', '2013-06-08 12:00:44 +0000', '0', 'subj', 'Hiss', 'ap19788'), ('pl2050411638', '', 'US32552', '2013-05-20 10:45:55 +0000', '0', 'TERI', 'Yahoooooooooo', 'ap19788'), ('pl1828600651', '', 'US32552', '2013-05-21 11:33:33 +0000', '0', 'test', 'Yest', 'ap19788'), ('pl549085534', '', 'US32552', '2013-05-19 11:45:04 +0000', '0', 'subj', 'Comment', 'ap19788'), ('pl665538927', '', 'US32552', '2013-05-29 11:45:41 +0000', '0', 'subj', '1234567890', 'ap19788'), ('pl1969438050', '', 'US32552', '2013-06-01 12:00:18 +0000', '0', 'subj', 'Cmt', 'ap19788'), ('pl672204050', '', 'US55240280', '2013-05-23 12:15:58 +0000', '0', 'aassdd', 'Cmt', 'ap19788'), ('pl1019026150', '', 'US32552', '2013-06-08 12:15:54 +0000', '0', 'exists', 'Cmt', 'ap19788'), ('pl790670523', '', 'US55240280', '2013-05-26 12:30:21 +0000', '0', 'qwerty', 'Cmt', 'ap19788') |
它在代码中也运行得很好,我可以成功地将所有内容保存在sqlite中。
在此之前,我使
我很惊讶没有人提到准备好的声明。除非您单独使用SQL,而不是在任何其他语言中使用SQL,否则我认为在事务中包装的准备好的语句将是插入多行的最有效方法。
你可以用插入器,既方便又快捷
文档: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,那么可以使用它:
1 2 3 4 5 6 | 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中,则需要执行以下操作:
1 2 3 4 5 6 7 | 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; |
它是如何工作的?如果表
1 2 3 4 | id INT ------ 1 2 |
然后
1 2 3 4 5 6 | a.id INT | b.id INT ------------------ 1 | 1 2 | 1 1 | 2 2 | 2 |
等等。在第一次执行之后,我们插入2行,然后2^3=8。(三是因为我们有
第二次执行后,我们插入额外的
第三次插入后,我们插入了大约4行,以此类推…
这是填充sqlite数据库的最快方法。