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

时间:2009-10-22 20:04:43

标签: sql sqlite syntax

在MySQL中,您可以插入多行,如下所示:

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

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

24 个答案:

答案 0 :(得分:584)

更新

作为BrianCampbell points out here SQLite 3.7.11及更高版本现在支持原始帖子的更简单语法。但是,如果您希望在旧数据库中实现最大兼容性,则显示的方法仍然适用。

原始答案

如果我有权限,我会碰到andy'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 vs UNION ALL的说明

正如有几个人评论的那样,如果您使用UNION ALL(如上所示),则会插入所有行,因此在这种情况下,您将获得四行data1, data2。如果省略ALL,则将删除重复的行(并且操作可能会慢一点)。我们正在使用UNION ALL,因为它更接近原始帖子的语义。

结束时

P.S。:请+1 andy's reply,而不是我的!他首先提出了解决方案。

答案 1 :(得分:546)

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

试试这个......

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

是的,它有点丑陋,但很容易从一组值自动生成语句。此外,您似乎只需要在第一个选择中声明列名称。

答案 2 :(得分:230)

是的,从SQLite 3.7.11开始,SQLite支持这一点。来自SQLite documentation

SQLite INSERT statement syntax

(最初编写此答案时,不支持此操作)

为了与旧版本的SQLite兼容,您可以使用andyfearless_fool使用UNION建议的技巧,但对于3.7.11及更高版本,此处描述的更简单的语法应该首选。

答案 3 :(得分:56)

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

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

答案 4 :(得分:37)

根据this page,不支持:

  
      
  • 2007-12-03:不支持多行INSERT a.k.a.复合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)   插入。这种或那种方式没有任何性能优势。“

答案 5 :(得分:14)

从版本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。不是我的!他首先提出了解决方案。

答案 6 :(得分:10)

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

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

答案 7 :(得分:10)

是的,sql可以这样做,但语法不同。顺便说一下,sqlite documentation非常好。 will also tell you插入多行的唯一方法是使用select语句作为要插入的数据的来源。

答案 8 :(得分:8)

除了通过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语句都是   自己的交易。但如果你   包含多个INSERT语句   与BEGIN ... COMMIT然后全部   插入被分组为一个   交易。提交所需的时间   交易按所有方式摊销   随附的插入语句等   每个插入语句的时间是   大大减少了。

     

另一种选择是运行PRAGMA   同步= OFF。这个命令会   导致SQLite不等待数据   到达磁盘表面,这将   使写操作看起来像   快多了。但如果你失去了力量   在交易的中间,你的   数据库文件可能已损坏。

答案 9 :(得分:8)

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

答案 10 :(得分:7)

fearless_fool对旧版本有很好的答案。我只是想补充一点,你需要确保列出所有列。因此,如果您有3列,则需要确保选择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)

答案 11 :(得分:7)

INSERT INTO TABLE_NAME 
            (DATA1, 
             DATA2) 
VALUES      (VAL1, 
             VAL2), 
            (VAL1, 
             VAL2), 
            (VAL1, 
             VAL2), 
            (VAL1, 
             VAL2), 
            (VAL1, 
             VAL2), 
            (VAL1, 
             VAL2), 
            (VAL1, 
             VAL2), 
            (VAL1, 
             VAL2); 

答案 12 :(得分:6)

在mysql lite中

你不能插入多个值, 但是你可以通过只打开一次连接然后完成所有插入然后关闭连接来节省时间。 它节省了大量时间

答案 13 :(得分:6)

你不能但我不认为你错过任何东西。

因为你总是在调用sqlite,所以无论你执行1个insert语句还是100个insert语句,性能几乎都无关紧要。然而,提交需要花费大量时间,因此将这100个插入内容放入事务中。

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

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

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

答案 14 :(得分:5)

使用事务的问题是您还要锁定表以供阅读。因此,如果您要插入大量数据并且需要访问数据,例如预览左右,这种方法效果不佳。

另一种解决方案的问题是您丢失了插入的顺序

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

在sqlite中,数据将存储a,b,c,d ......

答案 15 :(得分:5)

  

从版本3.7.11开始,SQLite支持多行插入。理查德   Hipp评论:

我正在使用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 +1

答案 16 :(得分:4)

INSERT INTO tabela(coluna1,coluna2) 
SELECT 'texto','outro'
UNION ALL 
SELECT 'mais texto','novo texto';

答案 17 :(得分:2)

我有一个如下所示的查询,但是使用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())

答案 18 :(得分:2)

关于sqlite 3.7.2:

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

等等

答案 19 :(得分:2)

我能够使查询动态化。这是我的表:

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查询内容动态但是开始出现一些语法错误。无论如何,这对我来说运行良好。

答案 20 :(得分:2)

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

事实上,它不支持此功能,但Sqlite Browser支持(适用于Windows,OS X,Linux)

答案 21 :(得分:1)

我很惊讶没有人提到准备好的陈述。除非您自己使用SQL而不使用任何其他语言,否则我认为包含在事务中的预处理语句将是插入多行的最有效方式

答案 22 :(得分:0)

答案 23 :(得分:-1)

如果您使用的是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

Aftern thrid我们插入约max(1000^3, 5e5)=500000行等等......

这是我最熟悉的填充SQLite数据库的方法。