webdevqa.jp.net

SQLiteデータベースに一度に複数の行を挿入することは可能ですか?

MySQLでは、このように複数の行を挿入できます。

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

しかし、このようなことをやろうとするとエラーになります。 SQLiteデータベースに一度に複数の行を挿入することは可能ですか?そのための構文は何ですか?

515
Andrew

更新

BrianCampbellがここで指摘していますSQLite 3.7.11以降では、元のpostの単純な構文がサポートされるようになりました。ただし、レガシーデータベース間で最大限の互換性が必要な場合は、示されているアプローチが依然として適切です。

元の答え

特権があれば、 andy's reply :YoucanSQLiteに複数の行を挿入します。必要なのは異なる構文。それを完全に明確にするために、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'

パフォーマンスに関する注意

私はもともとこの手法を使用して、Rails上のRubyから大きなデータセットを効率的に読み込みました。 ただし、Jaime Cookが指摘するように 、単一の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の4つの行を取得します。 ALLを省略すると、重複する行が削除されます(操作はおそらく少し遅くなります)。 UNION ALLを使用しているのは、元の投稿のセマンティクスにより厳密に一致しているためです。

最後に

追伸:+1してください アンディの返事 私ではなく!彼は最初に解決策を提示しました。

590
fearless_fool

はい、可能ですが、通常のコンマ区切りの挿入値ではできません。

これを試して...

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

はい、それは少し醜いですが、値のセットからステートメントの生成を自動化するのに十分簡単です。また、最初の選択では列名を宣言するだけでよいと思われます。

546
andy

はい、SQLiteの時点で 3.7.11 これはSQLiteでサポートされています。 SQLiteのドキュメントから

SQLite INSERT statement syntax

(この答えが最初に書かれたとき、これはサポートされませんでした)

古いバージョンのSQLiteとの互換性のために、 andy および fearless_fool で推奨されるUNIONを使用したトリックを使用できますが、3.7.11以降では、ここで説明されている簡単な構文が推奨されます。

230
Brian Campbell

一連のinsertステートメントから単一の500要素の複数行の挿入を生成するためのRubyコードをいくつか書きました。これは個々の挿入を実行するよりもかなり高速です。それから、複数の挿入を単一のトランザクションにラップすることを試みたところ、かなり少ないコードで同じ種類のスピードを上げることができることがわかりました。

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

このページ によると、サポートされていません:

  • 2007-12-03:複数行INSERT別名複合INSERTはサポートされていません。
  INSERT INTO table (col1, col2) VALUES 
      ('row1col1', 'row1col2'), ('row2col1', 'row2col2'), ...

実際には、SQL92標準によると、VALUES式はそれ自体で耐えることができるはずです。たとえば、次の例では3行の1列のテーブルが返されます。VALUES 'john', 'mary', 'paul';

バージョン3.7.11では、SQLiteのをサポートしています multi-row-insert をサポートしています。 Richard Hippのコメント:

「新しい多値挿入は、複合挿入に対する単なる構文上の問題ではありません。いずれにせよ、パフォーマンス上の利点はありません。」

37
typeseven

バージョン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してください。私のじゃない!彼は最初に解決策を提示しました。

14
mjb

はい、SQLはこれを実行できますが、構文は異なります。ちなみに sqliteのドキュメント はなかなかいいです。また、 は、複数の行を挿入する唯一の方法が 挿入するデータのソースとしてselectステートメント を使用することを に伝えます。

10
innaM

他のポスターが言ったように、SQLiteはこの構文をサポートしていません。複合INSERTがSQL標準の一部であるかどうかはわかりませんが、私の経験では、それらは多くの製品でnot実装されています。

余談ですが、明示的なトランザクションで複数のINSERTをラップすると、SQLiteのINSERTパフォーマンスが大幅に向上することに注意する必要があります。

10
Larry Lustig

Sqlite 3は、SELECTを使用する場合を除き、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> 

CLIの.importコマンドを使用するのではなく、INSERTの周囲にループを配置する場合は、INSERT速度についてsqlite FAQのアドバイスに従ってください。

デフォルトでは、各INSERT文はそれぞれ独自のトランザクションです。しかし、複数のINSERTステートメントをBEGIN ... COMMITで囲むと、すべての挿入が単一のトランザクションにまとめられます。トランザクションをコミットするのに必要な時間は、囲まれているすべての挿入ステートメントにわたって償却されるため、挿入ステートメントあたりの時間は大幅に短縮されます。

もう1つのオプションは、PRAGMA synchronization = OFFを実行することです。このコマンドはSQLiteがデータがディスク表面に到達するのを待たないようにします、それは書き込み操作がずっと速く見えるようにするでしょう。しかし、トランザクションの途中で電源が切れた場合、データベースファイルが破損する可能性があります。

8
DigitalRoss

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
8
AG1
INSERT INTO TABLE_NAME 
            (DATA1, 
             DATA2) 
VALUES      (VAL1, 
             VAL2), 
            (VAL1, 
             VAL2), 
            (VAL1, 
             VAL2), 
            (VAL1, 
             VAL2), 
            (VAL1, 
             VAL2), 
            (VAL1, 
             VAL2), 
            (VAL1, 
             VAL2), 
            (VAL1, 
             VAL2); 
7
aasai arun

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より)

7
LEO

mysql liteでは、複数の値を挿入することはできませんが、一度接続を開き、その後すべての挿入を行ってから接続を閉じることで時間を節約できます。それは多くの時間を節約します

6
g.revolution

あなたはできませんが、私はあなたが何かを逃すとは思わない。

Sqliteは常にインプロセスで呼び出されるので、1つのinsertステートメントを実行するのか、100つのinsertステートメントを実行するのかは、パフォーマンスにはほとんど関係ありません。しかしコミットにはかなりの時間がかかるため、トランザクション内に100個の挿入を入れてください。

Sqliteは、パラメータ化されたクエリを使用するとはるかに高速になるため(必要な構文解析がはるかに少なくなります)、このような大きなステートメントを連結しません。

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

すべての連結ステートメントは異なるため、それらは何度も何度も解析する必要があります。

6
tuinstoel

トランザクションを使用する際の問題は、読み取りのためにもテーブルをロックすることです。そのため、実際に挿入するデータが多く、プレビューなどに自分のデータにアクセスする必要がある場合、この方法はうまくいきません。

他の解決策の問題はあなたが挿入の順序を失うことです。

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

SQLiteでは、データはストアA、B、C、Dになります...

5
alex

バージョン3.7.11以降、SQLiteは複数行挿入をサポートしています。 Richard 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レコードを挿入すると、1秒以下しかかかりません。

Sqliteを使用して一度に複数の行を挿入することは非常に可能です。投稿者@Andy.

ありがとうアンディ+1

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

私は以下のようなクエリを持っていますが、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())
2
caglaror

クエリを動的にすることができます。これは私のテーブルです:

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クエリを動的にしていましたが、構文エラーが発生し始めました。とにかく、これは私にとってうまくいっています。

2
Vaibhav Saran

Sqlite manager firefoxプラグインを使用すると、INSERT SQLステートメントからの一括挿入がサポートされます。

Infactそれはこれをサポートしていませんが、 Sqlite Browser はします(Windows、OS X、Linuxで動作します)

2
Chris S

SQLite 3.7.2の場合:

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

等々

2
ashakirov

プリペアドステートメント について誰も言及していないことに驚きました。他の言語ではなくSQLを単独で使用しているのでない限り、 transaction にラップされた prepared statement が複数行を挿入する最も効率的な方法になると思います。

1
user918938

あなたは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/ /

編集:InsertHelperはAPIレベル17の時点で非推奨です

0
Mahmoud Badri