RESULT_SCAN
RESULT_SCAN
RESULT_SCAN 함수는 이전 명령(쿼리를 실행한 시점부터 24시간 이내)의 결과 집합을 테이블인 것처럼 반환해요. 이 함수는 다음 작업 중 하나의 출력을 처리하려 할 때 특히 유용해요:
- 실행한 SHOW 또는 DESC[RIBE] 명령.
- Snowflake 정보 스키마(Information Schema) 또는 계정 사용량(Account Usage) 같은 메타데이터나 계정 사용량 정보에 대해 실행한 쿼리.
- 호출한 저장 프로시저의 결과. RESULT_SCAN을 사용하는 대신 SELECT 문의 FROM 절에서 표 형식 데이터를 반환하는 저장 프로시저를 호출할 수도 있어요.
명령이나 쿼리는 현재 세션 또는 다른 세션(과거 세션 포함)에서 온 것일 수 있으며, 24시간 기간이 경과하지 않았는지만 확인하면 돼요. 이 기간은 조정할 수 없어요. 자세한 내용은 지속 쿼리 결과 사용(Persisted Query Results)을 참조하세요.
팁: 이 함수 대신 파이프 연산자(
->>)를 사용해 이전 명령의 결과를 처리할 수 있어요.
참고: DESCRIBE RESULT (계정 및 세션 DDL)도 참조하세요.
출처: 문서
본문
문법 (Syntax)
RESULT_SCAN ( [ { '<query_id>' | <query_index> | LAST_QUERY_ID() } ] )
인자 (Arguments)
- 'query_id' 또는 query_index 또는 LAST_QUERY_ID() — 지난 24시간 내 임의의 세션에서 실행한 쿼리에 대한 지정, 현재 세션에서 쿼리의 정수 인덱스, 또는 현재 세션의 쿼리 ID를 반환하는 LAST_QUERY_ID 함수이에요. Snowflake 쿼리 ID는
01b71944-0001-b181-0000-0129032279f6같은 고유한 문자열이에요. 쿼리 인덱스는 현재 세션의 첫 번째 쿼리(양수인 경우) 또는 가장 최근 쿼리(음수인 경우)를 기준으로 해요. 예를 들어RESULT_SCAN(-1)은RESULT_SCAN(LAST_QUERY_ID())과 같아요. 이 인자는 선택적이에요. 생략하면 기본값은RESULT_SCAN(-1)이며, 가장 최근 명령의 결과 집합을 반환해요.
사용 메모 (Usage notes)
- 원래 쿼리를 수동으로 실행했다면 원래 쿼리를 실행한 사용자만 RESULT_SCAN 함수를 사용해 쿼리 출력을 처리할 수 있어요. ACCOUNTADMIN 특권을 가진 사용자도 다른 사용자 쿼리의 결과를 RESULT_SCAN을 호출해 접근할 수 없어요.
- 원래 쿼리를 태스크(task)를 사용해 실행했다면 특정 사용자가 아니라 태스크를 소유한 역할이 쿼리를 트리거하고 실행했어요. 사용자나 태스크가 동일한 역할로 동작하면 RESULT_SCAN을 사용해 쿼리 결과에 접근할 수 있어요.
- Snowflake는 모든 쿼리 결과를 24시간 동안 저장해요. 이 함수는 이 시간 내에 실행된 쿼리에 대한 결과만 반환해요.
- 결과 집합에는 연관된 메타데이터가 없으므로 큰 결과를 처리하는 것은 실제 테이블을 조회할 때보다 느릴 수 있어요.
- RESULT_SCAN을 포함하는 쿼리에는 원래 쿼리에 없던 절(예: 필터와 ORDER BY 절)이 포함될 수 있어요. 이러한 절을 사용해 결과 집합을 좁히거나 수정할 수 있어요.
- RESULT_SCAN은 원래 쿼리가 행을 반환한 것과 동일한 순서로 행을 반환한다는 보장이 없어요. RESULT_SCAN 쿼리에 ORDER BY 절을 포함해 특정 순서를 지정할 수 있어요.
- 특정 쿼리의 ID를 검색하려면 다음 방법 중 하나를 사용해요:
- Snowsight: 다음 두 위치 중 하나에서 제공된 링크를 클릭해 ID를 표시하거나 복사해요: Projects 아래 Worksheets에서 쿼리 실행 후 Query Details에 ID 링크가 포함돼요. Monitoring 아래 Query History에서 각 쿼리에 ID 링크가 포함돼요.
- SQL: 다음 함수 중 하나를 호출해요:
QUERY_HISTORY,QUERY_HISTORY_BY_*테이블 함수.LAST_QUERY_ID함수 (쿼리가 현재 세션에서 실행된 경우). 예를 들어:SELECT LAST_QUERY_ID(-2);이는 RESULT_SCAN의 입력으로 LAST_QUERY_ID를 사용하는 것과 같아요.
- RESULT_SCAN이 중복 열 이름을 포함한 쿼리 출력을 처리하면(예: 열 이름이 겹치는 두 테이블을 조인한 쿼리) RESULT_SCAN은 수정된 이름으로 중복 열을 참조하며 원래 이름에
_1,_2등을 추가해요. 예제는 아래 예제 섹션을 참조하세요. - 벡터화된 스캐너로 조회한 Parquet 파일의 타임스탬프는 때때로 다른 시간대에 표시될 수 있어요. CONVERT_TIMEZONE 함수를 사용해 모든 타임스탬프 데이터를 표준 시간대로 변환하세요.
대조(collation) 세부사항
RESULT_SCAN이 이전 문의 결과를 반환할 때 RESULT_SCAN은 반환하는 값의 대조 지정을 보존해요.
예제 (Examples)
다음 예제들은 RESULT_SCAN 함수를 사용해요.
간단한 예제 (Simple examples)
현재 세션에서 가장 최근 쿼리 결과에서 1보다 큰 모든 값을 검색해요:
SELECT $1 AS value FROM VALUES (1), (2), (3);
+-------+
| VALUE |
|-------|
| 1 |
| 2 |
| 3 |
+-------+
SELECT * FROM TABLE(RESULT_SCAN(LAST_QUERY_ID())) WHERE value > 1;
+-------+
| VALUE |
|-------|
| 2 |
| 3 |
+-------+
현재 세션에서 두 번째로 최근인 쿼리의 모든 값을 검색해요:
SELECT * FROM TABLE(RESULT_SCAN(LAST_QUERY_ID(-2)));
현재 세션에서 첫 번째 쿼리의 모든 값을 검색해요:
SELECT * FROM TABLE(RESULT_SCAN(LAST_QUERY_ID(1)));
지정된 쿼리 결과에서 c2 열의 값을 검색해요:
SELECT c2 FROM TABLE(RESULT_SCAN('ce6687a4-331b-4a57-a061-02b2b0f0c17c'));
DESCRIBE 및 SHOW 명령을 사용한 예제
DESCRIBE USER 명령의 결과를 처리해 사용자의 기본 역할 같은 관심 있는 특정 필드를 검색해요. DESC USER 명령의 출력 열 이름이 소문자로 생성됐으므로, 명령은 쿼리의 열 이름에 큰따옴표로 묶인 식별자를 사용해 쿼리의 열 이름이 스캔되는 출력의 열 이름과 일치하도록 해요.
DESC USER jessicajones;
SELECT "property", "value" FROM TABLE(RESULT_SCAN(LAST_QUERY_ID()))
WHERE "property" = 'DEFAULT_ROLE';
SHOW TABLES 명령의 결과를 처리해 21일보다 오래된 빈 테이블을 추출해요. SHOW 명령은 소문자 열 이름을 생성하므로 명령은 일치하는 대소문자를 사용하기 위해 이름을 따옴표로 묶어요:
SHOW TABLES;
SELECT "database_name", "schema_name", "name" as "table_name", "rows", "created_on"
FROM table(RESULT_SCAN(LAST_QUERY_ID()))
WHERE "rows" = 0 AND "created_on" < DATEADD(day, -21, CURRENT_TIMESTAMP())
ORDER BY "created_on";
SHOW TABLES 명령의 결과를 처리해 크기 내림차순으로 테이블을 추출해요. 다음 예제는 UDF를 사용해 테이블 크기를 더 읽기 쉬운 형식으로 표시하는 방법도 보여줘요:
-- Show byte counts with suffixes such as "KB", "MB", and "GB".
CREATE OR REPLACE FUNCTION NiceBytes(NUMBER_OF_BYTES INTEGER)
RETURNS VARCHAR
AS
$$
CASE
WHEN NUMBER_OF_BYTES < 1024
THEN NUMBER_OF_BYTES::VARCHAR
WHEN NUMBER_OF_BYTES >= 1024 AND NUMBER_OF_BYTES < 1048576
THEN (NUMBER_OF_BYTES / 1024)::VARCHAR || 'KB'
WHEN NUMBER_OF_BYTES >= 1048576 AND NUMBER_OF_BYTES < (POW(2, 30))
THEN (NUMBER_OF_BYTES / 1048576)::VARCHAR || 'MB'
ELSE
(NUMBER_OF_BYTES / POW(2, 30))::VARCHAR || 'GB'
END
$$
;
SHOW TABLES;
-- Show all of my tables in descending order of size.
SELECT "database_name", "schema_name", "name" as "table_name", NiceBytes("bytes") AS "size"
FROM table(RESULT_SCAN(LAST_QUERY_ID()))
ORDER BY "bytes" DESC;
저장 프로시저를 사용한 예제
저장 프로시저 호출은 값을 반환해요. 그러나 이 값은 다른 문에 저장 프로시저 호출을 포함할 수 없기 때문에 직접 처리할 수 없어요. 이 제한을 해결하기 위해 RESULT_SCAN을 사용해 저장 프로시저가 반환한 값을 처리할 수 있어요. 아래에 간단한 예제가 있어요:
먼저 "복잡한" 값(이 경우 JSON 호환 데이터를 포함하는 문자열)을 반환하는 프로시저를 만들어요. 이 값은 CALL에서 반환된 후 처리할 수 있어요.
CREATE OR REPLACE PROCEDURE return_json()
RETURNS VARCHAR
LANGUAGE JavaScript
AS
$$
return '{"keyA": "ValueA", "keyB": "ValueB"}';
$$
;
프로시저를 호출해요:
CALL return_json();
+--------------------------------------+
| RETURN_JSON |
|--------------------------------------|
| {"keyA": "ValueA", "keyB": "ValueB"} |
+--------------------------------------+
다음 세 단계는 결과 집합에서 데이터를 추출해요.
첫 번째(그리고 유일한) 열을 얻어요:
SELECT $1 AS output_col FROM table(RESULT_SCAN(LAST_QUERY_ID()));
+--------------------------------------+
| OUTPUT_COL |
|--------------------------------------|
| {"keyA": "ValueA", "keyB": "ValueB"} |
+--------------------------------------+
출력을 VARCHAR 값에서 VARIANT 값으로 변환해요:
SELECT PARSE_JSON(output_col) AS json_col FROM TABLE(RESULT_SCAN(LAST_QUERY_ID()));
+---------------------+
| JSON_COL |
|---------------------|
| { |
| "keyA": "ValueA", |
| "keyB": "ValueB" |
| } |
+---------------------+
keyB 키에 해당하는 값을 추출해요:
SELECT json_col:keyB FROM TABLE(RESULT_SCAN(LAST_QUERY_ID()));
+---------------+
| JSON_COL:KEYB |
|---------------|
| "ValueB" |
+---------------+
다음 예제는 이전 예제에서 추출한 것과 동일한 데이터를 추출하는 더 간결한 방법을 보여줘요. 이 예제는 문이 더 적지만 읽기는 더 어려워요:
CALL return_json();
+--------------------------------------+
| RETURN_JSON |
|--------------------------------------|
| {"keyA": "ValueA", "keyB": "ValueB"} |
+--------------------------------------+
SELECT JSON_COL:keyB
FROM (
SELECT PARSE_JSON($1::VARIANT) AS json_col
FROM TABLE(RESULT_SCAN(LAST_QUERY_ID()))
);
+---------------+
| JSON_COL:KEYB |
|---------------|
| "ValueB" |
+---------------+
CALL의 출력은 함수 이름을 열 이름으로 사용해요. 쿼리에서 해당 열 이름을 사용할 수 있어요. 다음 예제는 열 번호 대신 이름으로 열을 참조하는 추가적인 간결한 버전을 보여줘요:
CALL return_json();
+--------------------------------------+
| RETURN_JSON |
|--------------------------------------|
| {"keyA": "ValueA", "keyB": "ValueB"} |
+--------------------------------------+
SELECT json_col:keyB
FROM (
SELECT PARSE_JSON(RETURN_JSON::VARIANT) AS json_col
FROM TABLE(RESULT_SCAN(LAST_QUERY_ID()))
);
+---------------+
| JSON_COL:KEYB |
|---------------|
| "ValueB" |
+---------------+
중복 열 이름을 가진 예제
다음 예제는 원래 쿼리에 중복 열 이름이 있을 때 RESULT_SCAN이 대체 열 이름을 효과적으로 참조한다는 것을 보여줘요:
같은 이름의 열을 최소 하나 이상 가진 두 테이블을 만들어요:
CREATE TABLE employees (id INT);
CREATE TABLE dependents (id INT, employee_id INT);
두 테이블에 데이터를 로드해요:
INSERT INTO employees (id) VALUES (11);
INSERT INTO dependents (id, employee_id) VALUES (101, 11);
이제 출력에 같은 이름의 열 두 개가 포함될 쿼리를 실행해요:
SELECT *
FROM employees INNER JOIN dependents
ON dependents.employee_ID = employees.id
ORDER BY employees.id, dependents.id;
+----+-----+-------------+
| ID | ID | EMPLOYEE_ID |
|----+-----+-------------|
| 11 | 101 | 11 |
+----+-----+-------------+
이제 RESULT_SCAN을 호출해 해당 쿼리의 결과를 처리해요. 결과에 같은 이름을 가진 서로 다른 열이 있으면 RESULT_SCAN은 첫 번째 열에 원래 이름을 사용하고 두 번째 열에 고유한 수정 이름을 할당해요. 이름을 고유하게 만들기 위해 RESULT_SCAN은 이름에 _n 접미사를 추가해요. 여기서 n은 이전 열 이름과 다른 이름을 생성하는 데 사용 가능한 다음 숫자예요.
SELECT id, id_1, employee_id
FROM TABLE(RESULT_SCAN(LAST_QUERY_ID()))
WHERE id_1 = 101;
+----+------+-------------+
| ID | ID_1 | EMPLOYEE_ID |
|----+------+-------------|
| 11 | 101 | 11 |
+----+------+-------------+