SQLite 데이터베이스에 한 번에 여러 행을 삽입 할 수 있습니까?


551

MySQL에서는 다음과 같이 여러 행을 삽입 할 수 있습니다.

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

그러나 이와 같은 작업을 시도하면 오류가 발생합니다. SQLite 데이터베이스에 한 번에 여러 행을 삽입 할 수 있습니까? 그렇게하는 구문은 무엇입니까?


26
이 질문은 일반적으로 SQL과는 달리 SQLite에 대해 구체적으로 묻는 것이기 때문에 속지 않습니다.
Brian Campbell


5
문제는 왜 그렇게해야 하는가입니다. SQlite가 동일한 기계에서 처리 중이므로 여러 인서트를 트랜잭션에 래핑 할 수 있으므로 필요가 없습니까?
andig

2
예, 버전 2012-03-20 (3.7.11)부터 시작하며 구문이 지원됩니다.
mjb

답변:


607

최신 정보

BrianCampbell이 여기서 지적한 대로 , SQLite 3.7.11 이상은 이제 원래 게시물의 더 간단한 구문을 지원합니다 . 그러나 레거시 데이터베이스에서 최대의 호환성을 원하는 경우 표시된 방법이 여전히 적합합니다.

원래 답변

권한이 있다면 리버의 대답 을 범할 것입니다. 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에서 대용량 데이터 세트를 효율적으로로드했습니다. 그러나 , 제이미 쿡 지적으로 , 그것은 개별 포장이는 빨리 분명하지 않다 INSERTs단일 트랜잭션 내에서 :

BEGIN TRANSACTION;
INSERT INTO 'tablename' table VALUES ('data1', 'data2');
INSERT INTO 'tablename' table VALUES ('data3', 'data4');
...
COMMIT;

효율성이 목표라면 먼저 시도해야합니다.

UNION과 UNION ALL에 대한 메모

여러 사람들이 언급했듯이 UNION ALL(위에 표시된 것처럼)을 사용하면 모든 행이 삽입되므로이 경우 4 개의 행이 나타납니다 data1, data2. 를 생략하면 ALL중복 행이 제거되고 작업이 약간 느려질 수 있습니다. UNION ALL은 원래 게시물의 의미와 더 가깝기 때문에 UNION ALL을 사용하고 있습니다.

닫는 중

추신 : 솔루션을 먼저 제시 했으므로 river 's reply +1하십시오 .


102
추가 참고로, SQLite는 단지 당신이 500 개 요소 블록 (으로 그것을 깰 필요가보다 더 많은 데이터를 던져하려고하는, 그래서 만약 쿼리 당 500 개 등의 노조 선택 개까지 지원하는 것 sqlite.org/limits.html )
Jamie Cook

3
합의 : SQLite는 병목 현상이 아니며 개별 ORM 트랜잭션 (제 경우에는 Ruby On Rails)의 오버 헤드입니다. 그래서 여전히 큰 승리입니다.
fearless_fool

3
이 솔루션 또는 3.7.11 솔루션은 트랜잭션 블록을 사용하는 것과 어떻게 비교됩니까? 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;?
Dan

5
추가 참고 사항으로 조심하십시오! 이 구문은 중복 행을 제거합니다! UNION ALL이를 피하기 위해 사용하십시오 (또는 약간의 성능 향상을 위해).
chacham15

1
@Shadowfax SQLite 버전을 확인하려면 (파이썬 모듈의 버전 일뿐 sqlite3.sqlite_version)이 아닌 sqlite3.version( 3.7.x 또는 3.8.x 여야 함 )을보십시오.
최대

562

가능하지만 일반적인 쉼표로 구분 된 삽입 값으로는 불가능합니다.

이 시도...

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

예, 값 집합에서 명령문 생성을 자동화 할 수있는 약간 추악하지만 쉽지 않습니다. 또한 첫 번째 선택에서만 열 이름을 선언하면됩니다.


36
사용 UNION ALL하지 마십시오 UNION. 중복을 제거하려는 경우를 제외하고.
Benoit

4
ID를 자동 증가 시키려면 NULL 값을 지정하십시오.
lenooh

241

예, SQLite 3.7.11부터는 SQLite에서 지원됩니다. 보내는 사람 SQLite는 설명서 :

SQLite INSERT 문 구문

(이 답변이 처음 작성된 경우 지원되지 않았습니다)

SQLite는 이전 버전과의 호환성을 위해, 당신은 제안 트릭 사용할 수 있습니다 앤디를 하고 fearless_fool 사용 UNION하지만 3.7.11 이후 여기에 설명 된 간단한 구문을 선호한다 위해.


3
나는 괄호 밖에 쉼표가있는 닫힌 루프가 있기 때문에 diagramm이 여러 행을 허용한다고 말하고 싶습니다 VALUES.
Johannes Gerer

@JohannesGerer이 이미지를 삽입 한 이후로 업데이트했습니다. 인터넷 아카이브에 다이어그램을 삽입 할 때 다이어그램을 볼 수 있습니다 . 실제로 2 개월 전에는 삽입에서 여러 행에 대한 지원을 추가했으며 이틀 전에 해당 변경 사항이있는 버전을 릴리스했습니다. 이에 따라 답변을 업데이트하겠습니다.
Brian Campbell

1
@ 브라이언, 당신은이 것을 그 상태, SQLite는 문서의 텍스트를 인용하시기 바랍니다 수 IS 가능? 나는 삽입 문서를 3 번 ​​다시 읽고 여러 행을 삽입하는 것에 대해 아무것도 찾지 못했지만이 그림 만 쉼표에 대해서는 아무것도 없었습니다 VALUES (...), (...):(
Prizoff

1
@Prizoff 테스트 케이스를 포함 하여이 지원이 추가 된 커밋에 연결했습니다 . 다이어그램에서 ( IA link 비교 ), 뒤에 표현식 주위에 루프 VALUES가 있으며 쉼표로 구분하여 반복 할 수 있음을 나타냅니다. 그리고 기능을 추가 한 버전 의 릴리스 노트 에 링크했습니다. "INSERT 구문을 강화하여 VALUES 절을 통해 여러 행을 삽입 할 수 있습니다."
Brian Campbell

1
@Prizoff 나는 이것을 SQLite 관리자에게 언급 했으며 문서 초안에서 사용할 수 있는 수정 사항커밋했습니다 . 다음 릴리스부터 공식 문서에있을 것이라고 생각합니다.
Brian Campbell

57

개별 인서트를 실행하는 것보다 훨씬 빠른 일련의 insert 문에서 단일 500 요소 다중 행 인서트를 생성하는 루비 코드를 작성했습니다. 그런 다음 여러 인서트를 단일 트랜잭션으로 래핑하려고 시도했지만 코드가 적 으면서 동일한 종류의 속도를 얻을 수 있음을 발견했습니다.

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

1
그러나 이것은 SQLite 관리자에서 직접 작업하는 동안 코드에서 작동하지 않았습니다. 코드에서는 첫 번째 행만 삽입합니다. (
Vaibhav Saran

4
내 코드 에서이 스타일의 삽입을 사용하고 있으며 완벽하게 작동합니다. 한 번에 모든 SQL을 제출해야합니다. 이것은 나에게 큰 속도 증가 였지만 허용 된 답변이 이것보다 빠르거나 느린 지 궁금합니다.
Dan

이 접근 방식은 단일 트랜잭션 내에서 여러 테이블을 수정할 때 실제로 확장되므로 데이터베이스를 일괄로드 할 때 자주 사용합니다.
Frank

바인딩을 사용해야하는 경우에는 이 방법 이 작동하지 않습니다 . SQLite3 엔진은 모든 바인딩이 첫 번째 명령문에 적용되는 것으로 가정하고 다음 명령문은 무시합니다. 자세한 설명 은이 SO 질문 을 참조하십시오 .
Philippe Hebert

38

이 페이지 에 따르면 지원되지 않습니다 :

  • 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 다중 행 삽입을 지원 합니다. 리차드 히프

"새로운 다중 값 인서트는 컴파운드 인서트에 대한 구문 적 suger (sic) 일뿐입니다. 어떤 방법 으로든 성능상의 이점은 없습니다."


어떤 방법 으로든 성능 이점이 없습니다. -그 말을 어디서 봤는지 말해 줄래? 어디서나 찾을 수 없었습니다.
Alix Axel

15

버전 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

추신 : Brian Campbell의 답변 / 답변에 +1하십시오. 내 것이 아닙니다! 그는 먼저 해결책을 제시했다.


10

다른 포스터가 말했듯이 SQLite는이 구문을 지원하지 않습니다. 복합 INSERT가 SQL 표준의 일부인지 모르겠지만 내 경험상 많은 제품에서 구현 되지 않았습니다 .

또한 명시적인 트랜잭션으로 여러 INSERT를 래핑하면 SQLite의 INSERT 성능이 크게 향상됩니다.


10

예, SQL 은이 작업을 수행 할 수 있지만 다른 구문으로 수행 할 수 있습니다. 그런데 sqlite 문서 는 꽤 좋습니다. 그것은 또한 당신을 말할 것이다 여러 행을 삽입 할 수있는 유일한 방법임을 select 문을 사용하여 데이터 소스를 삽입 할 수있다.


9

Sqlite3은 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으로 둘러싸면 모든 삽입이 단일 트랜잭션으로 그룹화됩니다. 트랜잭션을 커밋하는 데 필요한 시간은 동봉 된 모든 insert 문에 대해 상각되므로 insert 문당 시간이 크게 줄어 듭니다.

다른 옵션은 PRAGMA synchronous = OFF를 실행하는 것입니다. 이 명령은 SQLite가 데이터가 디스크 표면에 도달 할 때까지 기다리지 않게하므로 쓰기 작업이 훨씬 더 빠릅니다. 그러나 트랜잭션 도중에 전원이 끊기면 데이터베이스 파일이 손상 될 수 있습니다.


SQLite .import명령 의 소스 코드를 보면 입력 파일 (또는 tty)에서 행을 읽은 다음 해당 행에 대한 INSERT 문을 읽는 루프 일뿐입니다. 불행히도 효율성이 크게 향상되지는 않았습니다.
Bill Karwin

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

8

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

6

당신은 할 수 없지만 당신이 아무것도 그리워 생각하지 않습니다.

sqlite를 항상 프로세스에서 호출하기 때문에 1 개의 insert 문을 실행하든 100 개의 insert 문을 실행하든 성능에 거의 영향을 미치지 않습니다. 그러나 커밋에는 많은 시간이 걸리므로 100 개의 삽입을 트랜잭션 안에 넣습니다.

Sqlite는 매개 변수가있는 쿼리를 사용할 때 훨씬 더 빠르므로 구문 분석이 훨씬 적으므로 다음과 같이 큰 문장을 연결하지 않습니다.

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

연결된 모든 문장이 다르기 때문에 반복해서 구문 분석해야합니다.


6

mysql lite에서는 여러 값을 삽입 할 수 없지만 연결을 한 번만 연 다음 모든 삽입을 수행 한 다음 연결을 닫으면 시간을 절약 할 수 있습니다. 많은 시간을 절약합니다


5

트랜잭션 사용의 문제점은 읽기를 위해 테이블을 잠그는 것입니다. 따라서 실제로 삽입 할 데이터가 많고 데이터에 액세스해야하는 경우 (예 : 미리보기 등)이 방법으로는 효과가 없습니다.

다른 해결책의 문제점은 삽입 순서를 잃어 버린다는 것입니다.

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

sqlite에서 데이터는 a, b, c, d를 저장합니다 ...


5

버전 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 개의 레코드를 삽입하면 1 초도 걸리지 않습니다.

sqlite를 사용하여 한 번에 여러 행을 삽입하는 것이 가능합니다. @Andy가 썼습니다.

고마워 앤디 +1


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


2

아래와 같은 쿼리가 있지만 ODBC 드라이버를 사용하면 SQLite에 ""오류가 있습니다. HTA (Html ​​Application)에서 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

sqlite 3.7.2에서 :

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

등등


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쿼리를 동적으로 만들었지 만 구문 오류가 발생하기 시작했습니다. 어쨌든, 이것은 나를 위해 잘 돌아가고 있습니다.


2

나는 아무도 준비된 진술 을 언급하지 않은 것에 놀랐다 . 다른 언어가 아닌 SQL 자체를 사용하지 않는 한 트랜잭션에 래핑 된 준비된 명령문이 여러 행을 삽입하는 가장 효율적인 방법 이라고 생각합니다 .


1
준비된 진술은 항상 좋은 생각이지만 OP가 요구하는 질문과 전혀 관련이 없습니다. 그는 한 문장에 여러 데이터를 삽입하는 기본 구문이 무엇인지 묻고 있습니다.
Lakey


-1

bash 쉘을 사용하는 경우 다음을 사용할 수 있습니다.

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을 삽입합니다. (우리가 가지고 있기 때문에 3tab a, tab b, tab c )

두 번째 실행 후 추가 (2+8)^3=1000행 을 삽입 합니다

세번째 max(1000^3, 5e5)=500000행 에 대해 행 등 을 삽입 합니다 ...

이것은 SQLite 데이터베이스를 채우는 가장 빠른 방법입니다.


2
유용한 데이터 를 삽입하려는 경우에는 작동하지 않습니다 .
CL.

@CL. 그것은 사실이 아닙니다. 원하는 임의의 날짜 및 ID와 혼합 할 수 있습니다.
test30
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.