RESULTSET 작업하기

이 항목에서는 Snowflake Scripting에서 RESULTSET를 사용하는 방법에 대해 설명합니다.

소개

Snowflake Scripting에서 RESULTSET는 쿼리의 결과 세트를 가리키는 SQL 데이터 타입입니다.

RESULTSET는 결과에 대한 포인터일 뿐이므로 RESULTSET를 통해 결과에 액세스하려면 다음 중 하나를 수행해야 합니다.

  • TABLE(...) 구문을 사용하여 결과를 테이블로 검색합니다.

  • 커서 로 RESULTSET를 반복합니다.

이 두 가지의 예가 아래에 포함되어 있습니다.

커서와 RESULTSET의 차이점 이해하기

RESULTSET와 커서 는 둘 다 쿼리의 결과 세트에 대한 액세스를 제공합니다. 그러나 이러한 오브젝트는 다음과 같은 면에서 다릅니다.

  • 쿼리가 실행되는 시점.

    • 커서의 경우 커서에서 OPEN 명령을 실행할 때 쿼리가 실행됩니다.

    • RESULTSET의 경우 쿼리를 RESULTSET(DECLARE 섹션 또는 BEGIN … END 블록)에 할당하면 쿼리가 실행됩니다.

  • OPEN 명령에서 바인딩 지원.

    • 커서를 선언할 때 바인딩 매개 변수(? 문자)를 지정할 수 있습니다. 나중에 OPEN 명령을 실행할 때 USING 절의 해당 매개 변수에 변수를 바인딩할 수 있습니다.

    • RESULTSET는 OPEN 명령을 지원하지 않습니다. 그러나 결과 세트를 반환하기 전에 SQL 명령에서 변수를 바인딩할 수 있습니다.

일반적으로 쿼리의 결과 세트가 포함된 테이블을 반환하려는 경우 RESULTSET를 사용하는 것이 더 간단합니다. 하지만 커서를 사용하여 Snowflake 스크립팅 블록에서 테이블을 반환할 수도 있습니다. 이를 위해서는 커서를 RESULTSET_FROM_CURSOR(cursor) 로 전달하여 RESULTSET를 반환하고 해당 RESULTSET를 TABLE(...) 로 전달하면 됩니다. 커서에 대한 테이블 반환하기 섹션을 참조하십시오.

RESULTSET 선언하기

블록의 DECLARE 섹션 또는 블록의 BEGIN … END 섹션에서 RESULTSET를 선언할 수 있습니다.

  • DECLARE 섹션 내에서, RESULTSET 선언 구문 에 설명된 구문을 사용합니다. 예:

    DECLARE
      ...
      res RESULTSET DEFAULT (SELECT col1 FROM mytable ORDER BY col1);
    
    Copy
  • BEGIN … END 블록 내에서, RESULTSET 할당 구문 에 설명된 구문을 사용합니다. 예:

    BEGIN
      ...
      LET res RESULTSET := (SELECT col1 FROM mytable ORDER BY col1);
    
    Copy

선언된 RESULTSET에 쿼리 할당하기

이미 선언된 RESULTSET에 쿼리 결과를 할당하려면 다음 구문을 사용합니다.

<resultset_name> := [ ASYNC ] ( <query> ) ;
Copy

여기서:

resultset_name

RESULTSET의 이름입니다.

이름은 현재 범위 내에서 고유해야 합니다.

이름은 오브젝트 식별자 에 대한 명명 규칙을 따라야 합니다.

ASYNC

쿼리를 비동기 하위 작업으로 실행합니다.

쿼리는 SELECT 문과 DML 문을 포함한 모든 유효한 SQL 문(예: INSERT 또는 UPDATE)이 될 수 있습니다.

이 키워드를 생략하면 저장 프로시저는 하위 작업을 순차적으로 실행하고, 각 하위 작업은 실행 중인 하위 작업이 완료될 때까지 기다렸다가 시작합니다.

이 키워드를 사용하여 여러 하위 작업을 동시에 실행하면 효율성을 높이고 전체 실행 시간을 줄일 수 있습니다.

AWAITCANCEL 문을 사용하여 RESULTSET 에 대한 비동기 하위 작업을 관리할 수 있습니다.

query

RESULTSET에 할당할 쿼리입니다.

RESULTSET에 쿼리를 할당하는 방법:

DECLARE
  res RESULTSET;
BEGIN
  res := (SELECT col1 FROM mytable ORDER BY col1);
  ...
Copy

RESULTSET 에 쿼리를 할당하고 쿼리를 비동기 하위 작업으로 실행하려면 다음과 같이 하십시오.

DECLARE
  res RESULTSET;
BEGIN
  res := ASYNC (SELECT col1 FROM mytable ORDER BY col1);
  ...
Copy

쿼리에 대해 SQL 문자열을 동적으로 작성하려면 query(EXECUTE IMMEDIATE string_of_sql) 로 설정합니다. 예:

DECLARE
  res RESULTSET;
  col_name VARCHAR;
  select_statement VARCHAR;
BEGIN
  col_name := 'col1';
  select_statement := 'SELECT ' || col_name || ' FROM mytable';
  res := (EXECUTE IMMEDIATE :select_statement);
  RETURN TABLE(res);
END;
Copy

query 를 RESULTSET 에 대한 EXECUTE IMMEDIATE 문으로 설정할 수 있지만, 커서에 대해서는 이 작업을 수행할 수 없습니다.

RESULTSET 사용하기

RESULTSET에 대한 쿼리는 오브젝트가 해당 쿼리와 연결될 때 실행됩니다. 예:

  • RESULTSET를 선언하고 DEFAULT 절을 쿼리에 설정하면 해당 시점에서 쿼리가 실행됩니다.

  • := 연산자를 사용하여 RESULTSET에 쿼리를 할당하면 해당 시점에서 쿼리가 실행됩니다.

참고

RESULTSET는 쿼리의 결과 세트를 가리키기 때문에(쿼리의 결과 세트는 포함하지 않음) RESULTSET는 쿼리 결과가 캐시되는 동안(일반적으로 24시간)에만 유효합니다. 쿼리 결과 캐싱에 대한 자세한 내용은 지속형 쿼리 결과 사용하기 섹션을 참조하십시오.

쿼리가 실행되면 커서를 사용하여 결과에 액세스할 수 있습니다. 저장 프로시저에서 결과를 테이블로 반환할 수도 있습니다.

커서를 사용하여 RESULTSET의 데이터에 액세스하기

커서를 사용하여 RESULTSET의 데이터에 액세스하려면 오브젝트에 커서를 선언합니다. 예:

DECLARE
  ...
  res RESULTSET DEFAULT (SELECT col1 FROM mytable ORDER BY col1);
  c1 CURSOR FOR res;
Copy

RESULTSET에 커서를 선언하면 커서는 RESULTSET에 이미 있는 데이터에 액세스할 수 있습니다. 커서에서 OPEN 명령을 실행하면 RESULTSET에 대한 쿼리가 다시 실행되지 않습니다.

그런 다음 커서를 열고 커서를 사용하여 데이터를 가져올 수 있습니다.

참고

결과에 GEOGRAPHY 값이 포함된 경우 값을 GEOGRAPHY 유형으로 캐스트한 후에 GEOGRAPHY 입력 값을 예상하는 함수에 값을 전달해야 합니다. 커서를 사용하여 GEOGRAPHY 값 검색하기 섹션을 참조하십시오.

RESULTSET를 테이블로 반환하기

RESULTSET가 가리키는 결과를 반환하려면 RESULTSET를 TABLE(...) 에 전달합니다. 예:

CREATE PROCEDURE f()
  RETURNS TABLE(column_1 INTEGER, column_2 VARCHAR)
  ...
    RETURN TABLE(my_resultset_1);
  ...
Copy

이는 TABLE(...)테이블 함수 (예: RESULT_SCAN)와 함께 사용되는 방식과 유사합니다.

예와 같이, 테이블을 반환하는 저장 프로시저를 작성하는 경우, 저장 프로시저를 테이블을 반환하는 것으로 선언해야 합니다.

참고

현재, TABLE(resultset_name) 구문은 RETURN 문에서만 지원됩니다.

커서를 사용하여 RESULTSET에서 행을 가져온 경우에도, TABLE(resultset_name) 에 의해 반환된 테이블에는 (커서의 내부 행 포인터에서 시작하는 행뿐만 아니라) 여전히 모든 행이 포함되어 있습니다.

RESULTSET 데이터 타입의 제한 사항

RESULTSET 는 데이터 타입이지만, Snowflake는 아직 다음을 지원하지 않습니다.

  • RESULTSET 타입의 열 선언.

  • RESULTSET 타입의 매개 변수 선언 .

  • 저장 프로시저의 반환 유형을 RESULTSET으로 선언.

Snowflake는 Snowflake Scripting 내에서만 RESULTSET를 지원합니다.

또한 RESULTSET 를 테이블로 직접 사용할 수 없습니다. 예를 들어 다음은 유효하지 않습니다.

SELECT * FROM my_result_set;
Copy

RESULTSET 사용 예

다음 섹션에서는 RESULTSET를 사용하는 예를 제시합니다.

예제를 위한 데이터 설정하기

아래의 많은 예에서는 아래에 표시된 테이블과 데이터를 사용합니다.

CREATE OR REPLACE TABLE t001 (a INTEGER, b VARCHAR);
INSERT INTO t001 (a, b) VALUES
  (1, 'row1'),
  (2, 'row2');
Copy

예: 저장 프로시저에서 테이블 반환하기

다음 코드는 RESULTSET를 선언하고 RESULTSET가 가리키는 결과를 반환하는 방법을 보여줍니다. CREATE PROCEDURE 명령의 RETURNS 절은 저장 프로시저가 INTEGER 타입의 열 하나를 포함하는 테이블을 반환한다고 선언합니다.

블록 내부의 RETURN 문은 TABLE(...) 구문을 사용하여 결과를 테이블로 반환합니다.

저장 프로시저를 만듭니다.

CREATE OR REPLACE PROCEDURE test_sp()
RETURNS TABLE(a INTEGER)
LANGUAGE SQL
AS
  DECLARE
    res RESULTSET DEFAULT (SELECT a FROM t001 ORDER BY a);
  BEGIN
    RETURN TABLE(res);
  END;
Copy

참고: Python Connector 코드에서 SnowSQL, Classic Console 또는 execute_stream 또는 execute_string 메서드를 사용하는 경우 이 예제를 대신 사용하십시오(SnowSQL, Classic Console 및 Python Connector에서 Snowflake Scripting 사용하기 참조).

CREATE OR REPLACE PROCEDURE test_sp()
RETURNS TABLE(a INTEGER)
LANGUAGE SQL
AS
$$
  DECLARE
      res RESULTSET default (SELECT a FROM t001 ORDER BY a);
  BEGIN
      RETURN TABLE(res);
  END;
$$;
Copy

저장 프로시저를 호출합니다.

CALL test_sp();
Copy
+---+
| A |
|---|
| 1 |
| 2 |
+---+

또한 RESULT_SCAN 함수를 사용하여 저장 프로시저 호출의 결과를 처리할 수도 있습니다.

SELECT *
  FROM TABLE(RESULT_SCAN(LAST_QUERY_ID()))
  ORDER BY 1;
Copy
+---+
| A |
|---|
| 1 |
| 2 |
+---+

예: 동적으로 SQL 문 구성하기

SQL을 동적으로 구성할 수 있습니다. 다음은 이전 저장 프로시저와 동일한 쿼리를 실행하지만, 동적으로 구성된 SQL 문을 사용하는 예입니다.

CREATE OR REPLACE PROCEDURE test_sp_dynamic(table_name VARCHAR)
  RETURNS TABLE(a INTEGER)
  LANGUAGE SQL
AS
DECLARE
  res RESULTSET;
  query VARCHAR DEFAULT 'SELECT a FROM IDENTIFIER(?) ORDER BY a;';
BEGIN
  res := (EXECUTE IMMEDIATE :query USING(table_name));
  RETURN TABLE(res);
END;
Copy

참고: Python Connector 코드에서 SnowSQL, Classic Console 또는 execute_stream 또는 execute_string 메서드를 사용하는 경우 이 예제를 대신 사용하십시오(SnowSQL, Classic Console 및 Python Connector에서 Snowflake Scripting 사용하기 참조).

CREATE OR REPLACE PROCEDURE test_sp_dynamic(table_name VARCHAR)
RETURNS TABLE(a INTEGER)
LANGUAGE SQL
AS
$$
  DECLARE
    res RESULTSET;
    query VARCHAR DEFAULT 'SELECT a FROM IDENTIFIER(?) ORDER BY a;';
  BEGIN
    res := (EXECUTE IMMEDIATE :query USING(table_name));
    RETURN TABLE(res);
  END
$$
;
Copy

예를 실행하려면 저장 프로시저를 호출하고 테이블 이름을 전달합니다.

CALL test_sp_dynamic('t001');
Copy
+---+
| A |
|---|
| 1 |
| 2 |
+---+

예: DEFAULT 절 없이 RESULTSET 변수 선언하기

다음 코드는 DEFAULT 절 없이(즉, 쿼리를 RESULTSET와 연결하지 않고) RESULTSET를 선언한 다음 나중에 RESULTSET를 쿼리와 연결하는 방법을 보여줍니다.

CREATE OR REPLACE PROCEDURE test_sp_02()
RETURNS TABLE(a INTEGER)
LANGUAGE SQL
AS
  DECLARE
    res RESULTSET;
  BEGIN
    res := (SELECT a FROM t001 ORDER BY a);
    RETURN TABLE(res);
  END;
Copy

참고: Python Connector 코드에서 SnowSQL, Classic Console 또는 execute_stream 또는 execute_string 메서드를 사용하는 경우 이 예제를 대신 사용하십시오(SnowSQL, Classic Console 및 Python Connector에서 Snowflake Scripting 사용하기 참조).

CREATE OR REPLACE PROCEDURE test_sp_02()
RETURNS TABLE(a INTEGER)
LANGUAGE SQL
AS
$$
  DECLARE
      res RESULTSET;
  BEGIN
      res := (SELECT a FROM t001 ORDER BY a);
      RETURN TABLE(res);
  END;
$$;
Copy

예제를 실행하려면 저장 프로시저를 호출합니다.

CALL test_sp_02();
Copy
+---+
| A |
|---|
| 1 |
| 2 |
+---+

예: RESULTSET와 함께 CURSOR 사용하기

다음 코드는 커서 를 사용하여 RESULTSET의 행을 반복하는 방법을 보여줍니다.

저장 프로시저를 만듭니다.

CREATE OR REPLACE PROCEDURE test_sp_03()
RETURNS VARCHAR
LANGUAGE SQL
AS

DECLARE
  accumulator INTEGER DEFAULT 0;
  res1 RESULTSET DEFAULT (SELECT a FROM t001 ORDER BY a);
  cur1 CURSOR FOR res1;
BEGIN
  FOR row_variable IN cur1 DO
    accumulator := accumulator + row_variable.a;
  END FOR;
  RETURN accumulator::VARCHAR;
END;
Copy

참고: Python Connector 코드에서 SnowSQL, Classic Console 또는 execute_stream 또는 execute_string 메서드를 사용하는 경우 이 예제를 대신 사용하십시오(SnowSQL, Classic Console 및 Python Connector에서 Snowflake Scripting 사용하기 참조).

CREATE OR REPLACE PROCEDURE test_sp_03()
RETURNS INTEGER
LANGUAGE SQL
AS
$$
  DECLARE
    accumulator INTEGER DEFAULT 0;
    res1 RESULTSET DEFAULT (SELECT a FROM t001 ORDER BY a);
    cur1 CURSOR FOR res1;
  BEGIN
    FOR row_variable IN cur1 DO
        accumulator := accumulator + row_variable.a;
    END FOR;
    RETURN accumulator;
  END;
$$;
Copy

저장 프로시저를 호출하면 결과가 테이블의 a 값을 더합니다(1 + 2).

CALL test_sp_03();
Copy
+------------+
| TEST_SP_03 |
|------------|
| 3          |
+------------+

예: 테이블을 동시에 쿼리하는 하위 작업 실행하기

다음 코드는 ASYNC 키워드를 사용하여 테이블을 동시에 쿼리하는 여러 하위 작업을 실행하는 방법을 보여줍니다.

이 예에서는 다음 테이블의 데이터를 사용합니다.

CREATE OR REPLACE TABLE orders_q1_2024 (
  order_id INT,
  order_amount NUMBER(12,2));

INSERT INTO orders_q1_2024 VALUES (1, 500.00);
INSERT INTO orders_q1_2024 VALUES (2, 225.00);
INSERT INTO orders_q1_2024 VALUES (3, 725.00);
INSERT INTO orders_q1_2024 VALUES (4, 150.00);
INSERT INTO orders_q1_2024 VALUES (5, 900.00);

CREATE OR REPLACE TABLE orders_q2_2024 (
  order_id INT,
  order_amount NUMBER(12,2));

INSERT INTO orders_q2_2024 VALUES (1, 100.00);
INSERT INTO orders_q2_2024 VALUES (2, 645.00);
INSERT INTO orders_q2_2024 VALUES (3, 275.00);
INSERT INTO orders_q2_2024 VALUES (4, 800.00);
INSERT INTO orders_q2_2024 VALUES (5, 250.00);
Copy

다음 저장 프로시저는 다음 작업을 수행합니다.

  • 두 테이블에서 모든 행의 order_amount 값을 쿼리하고 그 결과를 서로 다른 RESULTSETs (각 테이블마다 하나씩)로 반환합니다.

  • ASYNC 키워드를 사용하여 쿼리가 동시 하위 작업으로 실행되도록 지정합니다.

  • 각 RESULTSET 에 대해 AWAIT 문을 실행하여 프로시저가 쿼리가 완료될 때까지 기다렸다가 계속 진행하도록 합니다. RESULTSET 에 대한 쿼리 결과는 AWAIT 가 RESULTSET 에 대해 실행될 때까지 액세스할 수 없습니다.

  • 커서를 사용하여 각 테이블에 대한 order_amount 행의 합계를 계산합니다.

  • 테이블의 합계를 더하고 값을 반환합니다.

CREATE OR REPLACE PROCEDURE test_sp_async_child_jobs_query()
RETURNS INTEGER
LANGUAGE SQL
AS
DECLARE
  accumulator1 INTEGER DEFAULT 0;
  accumulator2 INTEGER DEFAULT 0;
  res1 RESULTSET DEFAULT ASYNC (SELECT order_amount FROM orders_q1_2024);
  res2 RESULTSET DEFAULT ASYNC (SELECT order_amount FROM orders_q2_2024);
BEGIN
  AWAIT res1;
  LET cur1 CURSOR FOR res1;
  OPEN cur1;
  AWAIT res2;
  LET cur2 CURSOR FOR res2;
  OPEN cur2;
  FOR row_variable IN cur1 DO
      accumulator1 := accumulator1 + row_variable.order_amount;
  END FOR;
  FOR row_variable IN cur2 DO
      accumulator2 := accumulator2 + row_variable.order_amount;
  END FOR;
  RETURN accumulator1 + accumulator2;
END;
Copy

참고: Python Connector 코드에서 SnowSQL, Classic Console 또는 execute_stream 또는 execute_string 메서드를 사용하는 경우 이 예제를 대신 사용하십시오(SnowSQL, Classic Console 및 Python Connector에서 Snowflake Scripting 사용하기 참조).

CREATE OR REPLACE PROCEDURE test_sp_async_child_jobs_query()
RETURNS INTEGER
LANGUAGE SQL
AS
$$
  DECLARE
    accumulator1 INTEGER DEFAULT 0;
    accumulator2 INTEGER DEFAULT 0;
    res1 RESULTSET DEFAULT ASYNC (SELECT order_amount FROM orders_q1_2024);
    res2 RESULTSET DEFAULT ASYNC (SELECT order_amount FROM orders_q2_2024);
  BEGIN
    AWAIT res1;
    LET cur1 CURSOR FOR res1;
    OPEN cur1;
    AWAIT res2;
    LET cur2 CURSOR FOR res2;
    OPEN cur2;
    FOR row_variable IN cur1 DO
        accumulator1 := accumulator1 + row_variable.order_amount;
    END FOR;
    FOR row_variable IN cur2 DO
        accumulator2 := accumulator2 + row_variable.order_amount;
    END FOR;
    RETURN accumulator1 + accumulator2;
  END;
$$;
Copy

저장 프로시저를 호출합니다.

CALL test_sp_async_child_jobs_query();
Copy
+--------------------------------+
| TEST_SP_ASYNC_CHILD_JOBS_QUERY |
|--------------------------------|
|                           4570 |
+--------------------------------+

예: 테이블에 행을 동시에 삽입하는 하위 작업 실행하기

다음 코드는 ASYNC 키워드를 사용하여 테이블에 행을 삽입하는 여러 하위 작업을 동시에 실행하는 방법을 보여줍니다.

다음 저장 프로시저는 다음 작업을 수행합니다.

  • orders_q3_2024 테이블이 없는 경우 생성합니다.

  • 테이블에 삽입 결과를 저장하는 RESULTSETs, insert_1insert_2 를 2개 생성합니다. 저장 프로시저 인자는 테이블에 삽입되는 값을 지정합니다.

  • ASYNC 키워드를 사용하여 삽입이 동시 하위 작업으로 실행되도록 지정합니다.

  • 각 RESULTSET 에 대해 AWAIT 문을 실행하여 프로시저가 삽입이 완료될 때까지 기다렸다가 계속 진행하도록 합니다. RESULTSET 의 결과는 AWAIT 가 RESULTSET 에 대해 실행될 때까지 액세스할 수 없습니다.

  • orders_q3_2024 테이블에 쿼리 결과를 저장하는 RESULTSET res 를 새로 만듭니다.

  • 쿼리 결과를 반환합니다.

CREATE OR REPLACE PROCEDURE test_sp_async_child_jobs_insert(
  arg1 INT,
  arg2 NUMBER(12,2),
  arg3 INT,
  arg4 NUMBER(12,2))
RETURNS TABLE()
LANGUAGE SQL
AS
  BEGIN
   CREATE TABLE IF NOT EXISTS orders_q3_2024 (
      order_id INT,
      order_amount NUMBER(12,2));
    LET insert_1 RESULTSET := ASYNC (INSERT INTO orders_q3_2024 SELECT :arg1, :arg2);
    LET insert_2 RESULTSET := ASYNC (INSERT INTO orders_q3_2024 SELECT :arg3, :arg4);
    AWAIT insert_1;
    AWAIT insert_2;
    LET res RESULTSET := (SELECT * FROM orders_q3_2024 ORDER BY order_id);
    RETURN TABLE(res);
  END;
Copy

참고: Python Connector 코드에서 SnowSQL, Classic Console 또는 execute_stream 또는 execute_string 메서드를 사용하는 경우 이 예제를 대신 사용하십시오(SnowSQL, Classic Console 및 Python Connector에서 Snowflake Scripting 사용하기 참조).

CREATE OR REPLACE PROCEDURE test_sp_async_child_jobs_insert(
  arg1 INT,
  arg2 NUMBER(12,2),
  arg3 INT,
  arg4 NUMBER(12,2))
RETURNS TABLE()
LANGUAGE SQL
AS
$$
  BEGIN
   CREATE TABLE IF NOT EXISTS orders_q3_2024 (
      order_id INT,
      order_amount NUMBER(12,2));
    LET insert_1 RESULTSET := ASYNC (INSERT INTO orders_q3_2024 SELECT :arg1, :arg2);
    LET insert_2 RESULTSET := ASYNC (INSERT INTO orders_q3_2024 SELECT :arg3, :arg4);
    AWAIT insert_1;
    AWAIT insert_2;
    LET res RESULTSET := (SELECT * FROM orders_q3_2024 ORDER BY order_id);
    RETURN TABLE(res);
  END;
$$;
Copy

저장 프로시저를 호출합니다.

CALL test_sp_async_child_jobs_insert(1, 325, 2, 241);
Copy
+----------+--------------+
| ORDER_ID | ORDER_AMOUNT |
|----------+--------------|
|        1 |       325.00 |
|        2 |       241.00 |
+----------+--------------+

RESULTSET를 사용하는 추가적인 예

다음은 RESULTSET를 사용하는 추가적인 예입니다.