INSERT

INSERT

테이블에 하나 이상의 행을 삽입하여 테이블을 업데이트하는 명령이에요. 테이블의 각 열에 삽입되는 값은 명시적으로 지정하거나 쿼리의 결과일 수 있어요.

출처: 문서

본문

구문 (Syntax)

INSERT [ OVERWRITE ] INTO <target_table> [ ( <target_col_name> [ , ... ] ) ]
       {
           VALUES ( { <value> | DEFAULT | NULL } [ , ... ] ) [ , ( ... ) ]
         | <query>
       }

필수 파라미터 (Required parameters)

  • target_table — 행을 삽입할 대상 테이블을 지정해요.
  • VALUES ( value | DEFAULT | NULL [ , ... ] ) [ , ( ... ) ] — 대상 테이블의 해당 열에 삽입할 하나 이상의 값을 지정해요. VALUES 절에서 다음을 지정할 수 있어요:
    • value: 명시적으로 지정된 값을 삽입해요. 값은 리터럴 또는 단일 값으로 평가되는 표현식일 수 있어요.
    • DEFAULT: 대상 테이블의 해당 열에 대한 기본값을 삽입해요.
    • NULL: NULL 값을 삽입해요. 절의 각 값은 쉼표로 구분해야 해요. 절에서 값 집합을 추가로 지정하여 여러 행을 삽입할 수 있어요.
  • query — 해당 열에 삽입할 값을 반환하는 쿼리 문장을 지정해요. 이렇게 하면 하나 이상의 소스 테이블에서 대상 테이블로 행을 삽입할 수 있어요.

선택 파라미터 (Optional parameters)

  • OVERWRITE — 값 삽입 전에 대상 테이블을 잘라내야(truncate) 함을 지정해요. 이 옵션을 지정해도 테이블의 접근 제어 권한에는 영향을 주지 않아요. OVERWRITE가 있는 INSERT 문장은 현재 트랜잭션 범위 내에서 처리될 수 있어, 다음과 같은 트랜잭션을 커밋하는 DDL 문장을 피할 수 있어요:
DROP TABLE t;
CREATE TABLE t AS SELECT * FROM ... ;

기본값: 없음(삽입 전 대상 테이블을 잘라내지 않음).

  • ( target_col_name [ , ... ] ) — 해당 값이 삽입되는 대상 테이블의 하나 이상의 열을 지정해요. 지정된 대상 열의 수는 VALUES 절에 지정된 값 또는 열(값이 쿼리 결과인 경우)의 수와 일치해야 해요. 기본값: 없음(대상 테이블의 모든 열이 업데이트됨).

사용 메모 (Usage notes)

  • 단일 INSERT 명령으로 VALUES 절에서 쉼표로 구분된 값 집합을 추가로 지정하여 테이블에 여러 행을 삽입할 수 있어요. 예를 들어 다음 절은 3열 테이블에 3행을 삽입하며, 처음 두 행은 값 1, 2, 3이고 세 번째 행은 값 2, 3, 4예요:
VALUES ( 1, 2, 3 ) ,
    ( 1, 2, 3 ) ,
    ( 2, 3, 4 )
  • INSERT에 OVERWRITE 옵션을 사용하려면 테이블에 대한 DELETE 권한이 있는 역할을 사용해야 해요. OVERWRITE가 테이블의 기존 레코드를 삭제하기 때문이에요.
  • VALUES 절에서 일부 유형의 표현식은 지정할 수 없어요:
    • 하위 쿼리(Subqueries):
    ... VALUES (SELECT id FROM other_table)
    
    • 반정형(semi-structured) 또는 구조화(structured) 데이터 유형의 값:
    ... VALUES (ARRAY_CONSTRUCT(1, 2, 3))
    
    • 윈도우 함수(Window functions):
    ... VALUES (ROW_NUMBER() OVER (...))
    
    • 집계 함수(Aggregate functions):
    ... VALUES (SUM(x))
    
    VALUES 절의 대안으로 쿼리 절에서 표현식을 지정해요. 예를 들어 다음 표현식을:
    INSERT INTO table1 (ID, varchar1, variant1)
     VALUES (4, 'Fourier', PARSE_JSON('{ "key1": "value1", "key2": "value2" }'));
    
    다음 표현식으로 바꿀 수 있어요:
    INSERT INTO table1 (ID, varchar1, variant1)
     SELECT 4, 'Fourier', PARSE_JSON('{ "key1": "value1", "key2": "value2" }');
    
  • VALUES 절은 200,000행으로 제한돼요. 이 제한은 단일 INSERT INTO … VALUES 문장과 단일 INSERT INTO … SELECT … FROM VALUES 문장에 적용돼요. 대량 데이터 로드를 수행하려면 COPY INTO <table> 명령을 사용하는 것을 고려해요.
  • 하이브리드 테이블에 데이터를 삽입하는 방법은 별도 안내를 참조해요.

예시 (Examples)

쿼리를 사용한 단일 행 삽입

세 문자열 값을 날짜 또는 타임스탬프로 변환하여 mytable 테이블의 단일 행에 삽입해요:

CREATE OR REPLACE TABLE mytable (
  col1 DATE,
  col2 TIMESTAMP_NTZ,
  col3 TIMESTAMP_NTZ);

DESC TABLE mytable;
+------+------------------+--------+-------+---------+-------------+------------+-------+------------+---------+-------------+----------------+
| name | type             | kind   | null? | default | primary key | unique key | check | expression | comment | policy name | privacy domain |
|------+------------------+--------+-------+---------+-------------+------------+-------+------------+---------+-------------+----------------|
| COL1 | DATE             | COLUMN | Y     | NULL    | N           | N          | NULL  | NULL       | NULL    | NULL        | NULL           |
| COL2 | TIMESTAMP_NTZ(9) | COLUMN | Y     | NULL    | N           | N          | NULL  | NULL       | NULL    | NULL        | NULL           |
| COL3 | TIMESTAMP_NTZ(9) | COLUMN | Y     | NULL    | N           | N          | NULL  | NULL       | NULL    | NULL        | NULL           |
+------+------------------+--------+-------+---------+-------------+------------+-------+------------+---------+-------------+----------------+
INSERT INTO mytable
  SELECT
    TO_DATE('2013-05-08T23:39:20.123'),
    TO_TIMESTAMP('2013-05-08T23:39:20.123'),
    TO_TIMESTAMP('2013-05-08T23:39:20.123');

SELECT * FROM mytable;
+------------+-------------------------+-------------------------+
| COL1       | COL2                    | COL3                    |
|------------+-------------------------+-------------------------|
| 2013-05-08 | 2013-05-08 23:39:20.123 | 2013-05-08 23:39:20.123 |
+------------+-------------------------+-------------------------+

이전 예시와 유사하지만 테이블의 첫 번째와 세 번째 열만 업데이트하도록 지정해요:

INSERT INTO mytable (col1, col3)
  SELECT
    TO_DATE('2013-05-08T23:39:20.123'),
    TO_TIMESTAMP('2013-05-08T23:39:20.123');

SELECT * FROM mytable;
+------------+-------------------------+-------------------------+
| COL1       | COL2                    | COL3                    |
|------------+-------------------------+-------------------------|
| 2013-05-08 | 2013-05-08 23:39:20.123 | 2013-05-08 23:39:20.123 |
| 2013-05-08 | NULL                    | 2013-05-08 23:39:20.123 |
+------------+-------------------------+-------------------------+

명시적 값으로 여러 행 삽입

employees 테이블을 만들고 VALUES 절의 쉼표로 구분된 목록에서 값 집합을 제공하여 4행의 데이터를 삽입해요:

CREATE TABLE employees (
  first_name VARCHAR,
  last_name VARCHAR,
  workphone VARCHAR,
  city VARCHAR,
  postal_code VARCHAR);

INSERT INTO employees
  VALUES
    ('May', 'Franklin', '1-650-249-5198', 'San Francisco', 94115),
    ('Gillian', 'Patterson', '1-650-859-3954', 'San Francisco', 94115),
    ('Lysandra', 'Reeves', '1-212-759-3751', 'New York', 10018),
    ('Michael', 'Arnett', '1-650-230-8467', 'San Francisco', 94116);

SELECT * FROM employees;
+------------+-----------+----------------+---------------+-------------+
| FIRST_NAME | LAST_NAME | WORKPHONE      | CITY          | POSTAL_CODE |
|------------+-----------+----------------+---------------+-------------|
| May        | Franklin  | 1-650-249-5198 | San Francisco | 94115       |
| Gillian    | Patterson | 1-650-859-3954 | San Francisco | 94115       |
| Lysandra   | Reeves    | 1-212-759-3751 | New York      | 10018       |
| Michael    | Arnett    | 1-650-230-8467 | San Francisco | 94116       |
+------------+-----------+----------------+---------------+-------------+

다중 행 삽입에서 첫 번째 행의 데이터 유형이 지침으로 사용되므로 삽입된 값의 데이터 유형이 행 전체에서 일관적인지 확인해요. 테이블을 만들고 두 행을 삽입해요:

CREATE OR REPLACE TABLE demo_insert_type_mismatch (v VARCHAR);

첫 번째 삽입은 예상대로 동작해요:

INSERT INTO demo_insert_type_mismatch (v) VALUES
  ('three'),
  ('four');
+-------------------------+
| number of rows inserted |
|-------------------------|
|                       2 |
+-------------------------+

두 번째 삽입은 두 번째 행('d')의 값 데이터 유형이 첫 번째 행(3)의 숫자 데이터 유형과 다른 문자열이므로 실패해요. 두 값 모두 테이블 열의 데이터 유형인 VARCHAR로 강제 변환될 수 있어도 삽입은 실패해요:

INSERT INTO demo_insert_type_mismatch (v) VALUES
  (3),
  ('d');
100038 (22018): DML operation to table DEMO_INSERT_TYPE_MISMATCH failed on column V with error: Numeric value 'd' is not recognized

데이터 유형이 행 전체에서 일관적이면 삽입은 성공하고 두 숫자 값 모두 VARCHAR 데이터 유형으로 강제 변환돼요:

INSERT INTO demo_insert_type_mismatch (v) VALUES
  (3),
  (4);
+-------------------------+
| number of rows inserted |
|-------------------------|
|                       2 |
+-------------------------+

쿼리로 여러 행 삽입

contractors 테이블에서 employees 테이블로 여러 행의 데이터를 삽입해요:

  • worknum 열이 지역번호 650을 포함하는 행만 선택.
  • city 열에 NULL 값을 삽입.
SELECT * FROM employees;
+------------+-----------+----------------+---------------+-------------+
| FIRST_NAME | LAST_NAME | WORKPHONE      | CITY          | POSTAL_CODE |
|------------+-----------+----------------+---------------+-------------|
| May        | Franklin  | 1-650-249-5198 | San Francisco | 94115       |
| Gillian    | Patterson | 1-650-859-3954 | San Francisco | 94115       |
| Lysandra   | Reeves    | 1-212-759-3751 | New York      | 10018       |
| Michael    | Arnett    | 1-650-230-8467 | San Francisco | 94116       |
+------------+-----------+----------------+---------------+-------------+
CREATE TABLE contractors (
  contractor_first VARCHAR,
  contractor_last VARCHAR,
  worknum VARCHAR,
  city VARCHAR,
  zip_code VARCHAR);

INSERT INTO contractors
  VALUES
    ('Bradley', 'Greenbloom', '1-650-445-0676', 'San Francisco', 94110),
    ('Cole', 'Simpson', '1-212-285-8904', 'New York', 10001),
    ('Laurel', 'Slater', '1-650-633-4495', 'San Francisco', 94115);

SELECT * FROM contractors;
+------------------+-----------------+----------------+---------------+----------+
| CONTRACTOR_FIRST | CONTRACTOR_LAST | WORKNUM        | CITY          | ZIP_CODE |
|------------------+-----------------+----------------+---------------+----------|
| Bradley          | Greenbloom      | 1-650-445-0676 | San Francisco | 94110    |
| Cole             | Simpson         | 1-212-285-8904 | New York      | 10001    |
| Laurel           | Slater          | 1-650-633-4495 | San Francisco | 94115    |
+------------------+-----------------+----------------+---------------+----------+
INSERT INTO employees(first_name, last_name, workphone, city, postal_code)
  SELECT contractor_first, contractor_last, worknum, NULL, zip_code
    FROM contractors
    WHERE CONTAINS(worknum,'650');

SELECT * FROM employees;
+------------+------------+----------------+---------------+-------------+
| FIRST_NAME | LAST_NAME  | WORKPHONE      | CITY          | POSTAL_CODE |
|------------+------------+----------------+---------------+-------------|
| May        | Franklin   | 1-650-249-5198 | San Francisco | 94115       |
| Gillian    | Patterson  | 1-650-859-3954 | San Francisco | 94115       |
| Lysandra   | Reeves     | 1-212-759-3751 | New York      | 10018       |
| Michael    | Arnett     | 1-650-230-8467 | San Francisco | 94116       |
| Bradley    | Greenbloom | 1-650-445-0676 | NULL          | 94110       |
| Laurel     | Slater     | 1-650-633-4495 | NULL          | 94115       |
+------------+------------+----------------+---------------+-------------+

공통 테이블 표현식(common table expression)을 사용하여 contractors 테이블에서 employees 테이블로 여러 행의 데이터를 삽입해요:

INSERT INTO employees (first_name, last_name, workphone, city, postal_code)
  WITH cte AS
    (SELECT contractor_first AS first_name,
            contractor_last AS last_name,
            worknum AS workphone,
            city,
            zip_code AS postal_code
       FROM contractors)
  SELECT first_name, last_name, workphone, city, postal_code
    FROM cte;

두 테이블(emp_addr, emp_ph)의 열을 소스 테이블의 id 열에서 INNER JOIN을 사용하여 세 번째 테이블(emp)에 삽입해요:

INSERT INTO emp (id, first_name, last_name, city, postal_code, ph)
  SELECT a.id, a.first_name, a.last_name, a.city, a.postal_code, b.ph
    FROM emp_addr a
    INNER JOIN emp_ph b ON a.id = b.id;

JSON 데이터 여러 행 삽입

테이블의 VARIANT 열에 두 JSON 객체를 삽입해요:

CREATE TABLE prospects (column1 VARIANT);

INSERT INTO prospects
  SELECT PARSE_JSON(column1)
  FROM VALUES
  ('{
    "_id": "57a37f7d9e2b478c2d8a608b",
    "name": {
      "first": "Lydia",
      "last": "Williamson"
    },
    "company": "Miralinz",
    "email": "[email protected]",
    "phone": "+1 (914) 486-2525",
    "address": "268 Havens Place, Dunbar, Rhode Island, 02801"
  }')
  , ('{
    "_id": "57a37f7d622a2b1f90698c01",
    "name": {
      "first": "Denise",
      "last": "Holloway"
    },
    "company": "DIGIGEN",
    "email": "[email protected]",
    "phone": "+1 (979) 587-3021",
    "address": "441 Dover Street, Ada, New Mexico, 87105"
  }');

OVERWRITE를 사용한 삽입

이 예시는 employees 테이블에 새 레코드가 추가된 후 INSERT with OVERWRITE로 employees에서 sf_employees 테이블을 재구축해요.

두 테이블의 초기 데이터:

SELECT * FROM employees;
+------------+-----------+----------------+---------------+-------------+
| FIRST_NAME | LAST_NAME | WORKPHONE      | CITY          | POSTAL_CODE |
|------------+-----------+----------------+---------------+-------------|
| May        | Franklin  | 1-650-111-1111 | San Francisco | 94115       |
| Gillian    | Patterson | 1-650-222-2222 | San Francisco | 94115       |
| Lysandra   | Reeves    | 1-212-222-2222 | New York      | 10018       |
| Michael    | Arnett    | 1-650-333-3333 | San Francisco | 94116       |
+------------+-----------+----------------+---------------+-------------+
SELECT * FROM sf_employees;
+------------+-----------+----------------+---------------+-------------+
| FIRST_NAME | LAST_NAME | WORKPHONE      | CITY          | POSTAL_CODE |
|------------+-----------+----------------+---------------+-------------|
| Mary       | Smith     | 1-650-999-9999 | San Francisco | 94115       |
+------------+-----------+----------------+---------------+-------------+

이 문장은 OVERWRITE 절을 사용하여 sf_employees 테이블에 행을 삽입해요:

INSERT OVERWRITE INTO sf_employees
  SELECT * FROM employees
  WHERE city = 'San Francisco';

INSERT가 OVERWRITE 절을 사용했으므로 sf_employees의 이전 행은 사라져요:

SELECT * FROM sf_employees;
+------------+-----------+----------------+---------------+-------------+
| FIRST_NAME | LAST_NAME | WORKPHONE      | CITY          | POSTAL_CODE |
|------------+-----------+----------------+---------------+-------------|
| May        | Franklin  | 1-650-111-1111 | San Francisco | 94115       |
| Gillian    | Patterson | 1-650-222-2222 | San Francisco | 94115       |
| Michael    | Arnett    | 1-650-333-3333 | San Francisco | 94116       |
+------------+-----------+----------------+---------------+-------------+

v3 Apache Iceberg™ 테이블에 쓰기

다음 예시는 Apache Iceberg™ 테이블 사양의 v3를 따르는 Apache Iceberg™ 테이블에 행을 삽입해요:

INSERT INTO my_v3_iceberg_table (id, payload) VALUES (1, PARSE_JSON('{"name": "Alice", "age": 30}'));

더 알아보기 (Learn more)