在 MySQL 中,您可以像这样插入多行:
INSERT INTO 'tablename' ('column1', 'column2') VALUES
('data1', 'data2'),
('data1', 'data2'),
('data1', 'data2'),
('data1', 'data2');
但是,当我尝试执行此类操作时出现错误。是否可以在 SQLite 数据库中一次插入多行?这样做的语法是什么?
更新
与 BrianCampbell points out here 一样,SQLite 3.7.11 及更高版本现在支持原始帖子的更简单语法。但是,如果您希望在旧数据库之间实现最大兼容性,则显示的方法仍然适用。
原始答案
如果我有特权,我会碰river's reply:你可以在 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 加载大型数据集。 但是,as Jaime Cook points out,尚不清楚在单个事务中包装单个 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 因为它更接近原始帖子的语义。
最后
PS:请+1 river's reply,因为它首先提出了解决方案。
是的,这是可能的,但不能使用通常的逗号分隔的插入值。
尝试这个...
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 documentation:
https://www.sqlite.org/images/syntax/insert-stmt.gif
(最初编写此答案时,不支持此功能)
为了与旧版本的 SQLite 兼容,您可以使用 andy 和 fearless_fool 建议的技巧,使用 UNION
,但对于 3.7.11 及更高版本,应首选此处描述的更简单的语法。
VALUES
之后的括号外有一个带有逗号的闭环。
VALUES (...), (...)
中没有关于逗号的内容):(
VALUES
之后的表达式周围有一个循环,表明它可以重复,用逗号分隔。我链接到 release notes 以添加添加该功能的版本,其中声明“增强 INSERT 语法以允许通过 VALUES 子句插入多行”。
我编写了一些 ruby 代码,从一系列插入语句生成单个 500 个元素的多行插入,这比运行单个插入要快得多。然后我尝试简单地将多个插入包装到一个事务中,发现我可以用少得多的代码获得同样的速度。
BEGIN TRANSACTION;
INSERT INTO table VALUES (1,1,1,1);
INSERT INTO table VALUES (2,2,2,2);
...
COMMIT;
根据 this page,不支持:
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。理查德·希普评论:
“新的多值插入只是复合插入的语法糖(原文如此)。无论哪种方式都没有性能优势。”
从版本 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 对 Brian Campbell 的回复/回答。不是我的!他首先提出了解决方案。
正如其他发帖人所说,SQLite 不支持这种语法。我不知道复合 INSERT 是否是 SQL 标准的一部分,但根据我的经验,它们并没有在许多产品中实现。
顺便说一句,您应该知道,如果您将多个 INSERT 包装在显式事务中,SQLite 中的 INSERT 性能会大大提高。
除了通过 SELECT 之外,Sqlite3 不能直接在 SQL 中执行此操作,虽然 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 synchronous=OFF。此命令将导致 SQLite 不等待数据到达磁盘表面,这将使写入操作看起来要快得多。但是,如果您在事务处理过程中断电,您的数据库文件可能会损坏。
.import
命令的源代码,它只是一个循环,从输入文件(或 tty)读取一行,然后为该行读取一个 INSERT 语句。不幸的是没有显着提高效率。
INSERT INTO TABLE_NAME
(DATA1, DATA2)
VALUES (VAL1, VAL2),
(VAL1, VAL2),
(VAL1, VAL2),
(VAL1, VAL2),
(VAL1, VAL2),
(VAL1, VAL2),
(VAL1, VAL2),
(VAL1, VAL2);
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
无畏的傻瓜对旧版本有一个很好的答案。我只是想补充一点,您需要确保列出了所有列。因此,如果您有 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)
你不能,但我认为你不会错过任何东西。
因为您总是在进程中调用 sqlite,所以无论您执行 1 个插入语句还是 100 个插入语句,性能几乎都无关紧要。然而,提交需要很多时间,所以将这 100 个插入放在一个事务中。
当您使用参数化查询(需要的解析要少得多)时,Sqlite 会快得多,所以我不会像这样连接大语句:
insert into mytable (col1, col2)
select 'a','b'
union
select 'c','d'
union ...
它们需要一次又一次地解析,因为每个连接的语句都是不同的。
在 mysql lite 中,您不能插入多个值,但您可以通过仅打开一次连接然后执行所有插入然后关闭连接来节省时间。它节省了很多时间
使用事务的问题是您还锁定表以供读取。因此,如果您有非常多的数据要插入并且您需要访问您的数据,例如预览左右,这种方式效果不佳。
另一种解决方案的问题是您丢失了插入的顺序
insert into mytable (col)
select 'c'
union
select 'd'
union
select 'a'
union
select 'b';
在sqlite中,数据将存储a,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 条记录,只需一秒钟或更短的时间。
确实使用 sqlite 一次插入多行是非常有可能的。由@Andy 写道。
谢谢安迪+1
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)
在 sqlite 3.7.2 上:
INSERT INTO table_name (column1, column2)
SELECT 'value1', 'value1'
UNION SELECT 'value2', 'value2'
UNION SELECT 'value3', 'value3'
等等
我能够使查询动态化。这是我的桌子:
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
查询内容动态化,但开始给出一些语法错误。无论如何,这对我来说运行良好。
我很惊讶没有人提到准备好的陈述。除非您自己使用 SQL 而不是在任何其他语言中使用 SQL,否则我认为包装在事务中的准备好的语句将是插入多行的最有效方式。
简单的。不言自明。
测试版本 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 |
有人可能会说 - 所有“.. UNION ..”的答案都已过时;然而,它们非常有用。有时我们都坐在办公桌上“过去的爆炸”,然后 15 岁的便条拯救了我们的一天。
我有一个像下面这样的查询,但是使用 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())
您可以使用 InsertHelper,它既简单又快速
文档:http://developer.android.com/reference/android/database/DatabaseUtils.InsertHelper.html
编辑:InsertHelper 自 API 级别 17 起已弃用
如果您使用的是 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 数据库的方法。
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
来避免这种情况(或一些小的性能提升)。