커서 작업하기¶
커서를 사용하여 쿼리 결과를 한 번에 한 행씩 반복할 수 있습니다.
이 항목의 내용:
소개¶
쿼리 결과에서 데이터를 검색하려면 커서를 사용합니다. 루프 에서 커서를 사용하여 결과의 행을 반복할 수 있습니다.
커서를 사용하려면 다음을 수행하십시오.
예에 대한 데이터 설정하기¶
이 섹션의 예에서는 다음 데이터를 사용합니다.
CREATE OR REPLACE TABLE invoices (id INTEGER, price NUMBER(12, 2)); INSERT INTO invoices (id, price) VALUES (1, 11.11), (2, 22.22);
커서 선언하기¶
SELECT 문 또는 RESULTSET 에 대한 커서를 선언할 수 있습니다.
블록의 DECLARE 섹션 또는 블록의 BEGIN … END 섹션에서 커서를 선언합니다.
DECLARE 섹션 내에서, 커서 선언 구문 에 설명된 구문을 사용합니다.
예를 들어 쿼리에 대한 커서를 선언하려면:
DECLARE ... c1 CURSOR FOR SELECT price FROM invoices;
RESULTSET에 대한 커서를 선언하려면:
DECLARE ... res RESULTSET DEFAULT (SELECT price FROM invoices); c1 CURSOR FOR res;
BEGIN … END 블록 내에서, 커서 할당 구문 에 설명된 구문을 사용합니다. 예:
BEGIN ... LET c1 CURSOR FOR SELECT price FROM invoices;
SELECT 문에서, 커서를 열 때 변수에 바인딩할 수 있는 바인딩 매개 변수(?
문자)를 지정할 수 있습니다. 변수를 매개 변수에 바인딩하려면 OPEN 명령의 USING 절에 변수를 지정합니다. 예:
DECLARE id INTEGER DEFAULT 0; minimum_price NUMBER(13,2) DEFAULT 22.00; maximum_price NUMBER(13,2) DEFAULT 33.00; c1 CURSOR FOR SELECT id FROM invoices WHERE price > ? and price < ?; BEGIN OPEN c1 USING (minimum_price, maximum_price); FETCH c1 INTO id; RETURN id; END;참고: SnowSQL 또는 Classic Console 을 사용하는 경우 대신 다음 예를 사용하십시오(SnowSQL 및 Classic Console 에서 Snowflake Scripting 사용하기 참조).
EXECUTE IMMEDIATE $$ DECLARE id INTEGER DEFAULT 0; minimum_price NUMBER(13,2) DEFAULT 22.00; maximum_price NUMBER(13,2) DEFAULT 33.00; c1 CURSOR FOR SELECT id FROM invoices WHERE price > ? and price < ?; BEGIN OPEN c1 USING (minimum_price, maximum_price); FETCH c1 INTO id; RETURN id; END; $$ ;
커서 열기¶
커서를 선언하는 문이 해당 커서와 연결된 쿼리를 정의하지만, 쿼리는 OPEN 명령을 실행하여 커서를 열 때까지 실행되지 않습니다. 예:
OPEN c1;
참고
FOR 루프에서 커서를 사용할 때 커서를 명시적으로 열 필요가 없습니다.
RESULTSET 오브젝트에 대한 커서를 선언하는 경우, 오브젝트를 쿼리와 연결할 때 쿼리가 실행됩니다. 이 경우 커서를 열어도 쿼리가 다시 실행되지 않습니다.
쿼리에 바인딩 매개 변수(?
문자)가 포함된 경우 USING
절을 추가하여, 해당 매개 변수에 바인딩할 변수 목록을 지정합니다. 예:
LET c1 CURSOR FOR SELECT id FROM invoices WHERE price > ? and price < ?; OPEN c1 USING (minimum_price, maximum_price);
커서를 열면 쿼리가 실행되고, 지정된 행을 커서로 가져오고, 첫 번째 행을 가리키는 내부 포인터를 설정합니다. FETCH
명령을 사용하여 커서를 사용해 개별 행을 가져올(읽을) 수 있습니다.
다른 SQL 쿼리와 마찬가지로, 쿼리 정의에서 가장 바깥쪽 수준에 ORDER BY가 포함되어 있지 않으면 결과 세트에는 정의된 순서가 없습니다. 커서에 대한 결과 세트가 만들어지면 커서가 닫힐 때까지 행의 순서가 유지됩니다. 커서를 다시 선언하거나 열면 행의 순서가 다를 수 있습니다. 마찬가지로, 커서를 닫고, 커서를 다시 열기 전에 기본 테이블이 업데이트되면 결과 세트도 변경될 수 있습니다.
커서를 사용하여 데이터 가져오기¶
FETCH 명령을 사용하여 결과 세트에서 현재 행을 검색하고, 내부 현재 행 포인터를 진행하여 결과 세트의 다음 행을 가리키도록 합니다.
INTO
절에서, 행의 값을 유지하는 데 사용해야 하는 변수를 지정합니다.
예:
FETCH c1 INTO var_for_column_value;
커서 선언의 SELECT 절에 있는 식 수와 변수 수가 일치하지 않는 경우 Snowflake는 위치별로 변수를 열과 일치시키려고 시도합니다.
열보다 변수가 더 많은 경우 Snowflake는 나머지 변수를 설정하지 않은 상태로 둡니다.
변수보다 열이 더 많은 경우 Snowflake는 나머지 열을 무시합니다.
실행하는 각 후속 FETCH
명령은 마지막 행을 가져올 때까지 다음 행을 가져옵니다.니다. FETCH 작업에 지연 시간이 발생할 수 있습니다. 마지막 행 다음에 행에 대한 FETCH 작업을 하려고 하면 NULL 값을 얻습니다.
RESULTSET 또는 CURSOR는 쿼리 실행 시점에서 결과 세트의 모든 행을 반드시 캐시하지는 않습니다. FETCH 작업에 지연이 발생할 수 있습니다.
커서를 사용하여 GEOGRAPHY 값 검색하기¶
결과에 GEOGRAPHY 유형의 열이 포함된 경우 열에 있는 값의 유형은 GEOGRAPHY가 아니라 OBJECT입니다. 즉, GEOGRAPHY 오브젝트를 입력으로 받아들이는 지리 공간적 함수 에 이 값을 직접 전달할 수 없다는 뜻입니다.
DECLARE
geohash_value VARCHAR;
BEGIN
LET res RESULTSET := (SELECT TO_GEOGRAPHY('POINT(1 1)') AS GEOGRAPHY_VALUE);
LET cur CURSOR FOR res;
FOR row_variable IN cur DO
geohash_value := ST_GEOHASH(row_variable.geography_value);
END FOR;
RETURN geohash_value;
END;
001044 (42P13): Uncaught exception of type 'EXPRESSION_ERROR' on line 7 at position 21 : SQL compilation error: ...
Invalid argument types for function 'ST_GEOHASH': (OBJECT)
이 문제를 해결하려면 열 값을 GEOGRAPHY 유형으로 캐스트하십시오.
geohash_value := ST_GEOHASH(TO_GEOGRAPHY(row_variable.geography_value));
커서에 대한 테이블 반환하기¶
커서에서 데이터 테이블을 반환해야 하는 경우, 커서를 RESULTSET_FROM_CURSOR(cursor)
에 전달할 수 있으며, 이는 차례로 TABLE(...)
에 전달할 수 있습니다.
다음 블록은 커서에서 데이터 테이블을 반환합니다.
DECLARE c1 CURSOR FOR SELECT * FROM invoices; BEGIN OPEN c1; RETURN TABLE(RESULTSET_FROM_CURSOR(c1)); END;참고: SnowSQL 또는 Classic Console 을 사용하는 경우 대신 다음 예를 사용하십시오(SnowSQL 및 Classic Console 에서 Snowflake Scripting 사용하기 참조).
EXECUTE IMMEDIATE $$ DECLARE c1 CURSOR FOR SELECT * FROM invoices; BEGIN OPEN c1; RETURN TABLE(RESULTSET_FROM_CURSOR(c1)); END; $$ ;
이 예는 다음과 같은 출력을 생성합니다.
+----+-------+ | ID | PRICE | |----+-------| | 1 | 11.11 | | 2 | 22.22 | +----+-------+
행을 가져오기 위해 이미 커서를 사용한 경우에도 RESULTSET_FROM_CURSOR
는 내부 행 포인터에서 시작하는 행뿐만 아니라 모든 행을 포함하는 RESULTSET를 반환합니다.
위에 표시된 대로 예는 첫 번째 행을 가져오고 내부 행 포인터를 두 번째 행으로 설정합니다. RESULTSET_FROM_CURSOR
는 (두 번째 행뿐만 아니라) 두 행을 모두 포함하는 RESULTSET를 반환합니다.
커서 닫기¶
결과 세트 작업이 끝나면 CLOSE 명령을 실행하여 커서를 닫습니다. 예:
CLOSE c1;
참고
FOR 루프에서 커서를 사용할 때 커서를 명시적으로 닫을 필요가 없습니다.
닫힌 커서에서는 FETCH
명령을 실행할 수 없습니다.
또한, 커서를 닫으면 현재 행 포인터가 무효화됩니다. 커서를 다시 열면 포인터가 새 결과 세트의 첫 번째 행을 가리킵니다.
커서 사용 예¶
이 예에서는 예에 대한 데이터 설정하기 에서 설정한 데이터를 사용합니다.
다음은 커서를 사용하여 두 행을 읽고 해당 행의 가격을 합산하는 저장 프로시저입니다.
DECLARE row_price FLOAT; total_price FLOAT; c1 CURSOR FOR SELECT price FROM invoices; BEGIN row_price := 0.0; total_price := 0.0; OPEN c1; FETCH c1 INTO row_price; total_price := total_price + row_price; FETCH c1 INTO row_price; total_price := total_price + row_price; CLOSE c1; RETURN total_price; END;참고: SnowSQL 또는 Classic Console 을 사용하는 경우 대신 다음 예를 사용하십시오(SnowSQL 및 Classic Console 에서 Snowflake Scripting 사용하기 참조).
EXECUTE IMMEDIATE $$ DECLARE row_price FLOAT; total_price FLOAT; c1 CURSOR FOR SELECT price FROM invoices; BEGIN row_price := 0.0; total_price := 0.0; OPEN c1; FETCH c1 INTO row_price; total_price := total_price + row_price; FETCH c1 INTO row_price; total_price := total_price + row_price; CLOSE c1; RETURN total_price; END; $$ ;
이 예는 다음과 같은 출력을 생성합니다.
+-----------------+ | anonymous block | |-----------------| | 33.33 | +-----------------+
루프를 사용하는 예는 FOR 루프 설명서에 포함되어 있습니다.
커서 문제 해결하기¶
증상: 커서가 모든 행이 아니라 모든 두 번째 행을 검색하는 것 같습니다.
- 가능한 원인:
FOR <레코드> IN <커서>
루프 내에서FETCH
를 실행했을 수 있습니다. 커서에 대한FOR
루프는 자동으로 다음 행을 가져옵니다. 루프 내에서 다른 가져오기를 수행하면 모든 두 번째 행을 가져옵니다.- 가능한 해결책:
FOR
루프 내에서 불필요한FETCH
를 제거합니다.
증상: FETCH 명령이 예기치 않은 NULL 값을 검색합니다.
- 가능한 원인:
FOR <레코드> IN <커서>
루프 내에서FETCH
를 실행했을 수 있습니다. 커서에 대한FOR
루프는 자동으로 다음 행을 가져옵니다. 루프 내에서 다른 가져오기를 수행하면 모든 두 번째 행을 가져옵니다. 행 수가 홀수인 경우 마지막FETCH
는 마지막 행을 넘어 행을 가져오려고 시도하고 값은 NULL이 됩니다.- 가능한 해결책:
FOR
루프 내에서 불필요한FETCH
를 제거합니다.