테이블 함수

테이블 함수 (Table functions)

테이블 함수는 테이블을 반환하는 함수예요. 쿼리의 FROM 절 안에서 호출할 수 있어요. 테이블 함수를 사용하면 SQL 쿼리 안에서 직접 커스텀 로직을 동적으로 호출할 수 있어요.

출처: 문서

본문

테이블 함수는 테이블을 반환하는 함수예요. 쿼리의 FROM 절 안에서 호출할 수 있어요.

SELECT * FROM TABLE(my_function(1, 100))

반환되는 테이블의 행 타입(row type)은 함수 호출 시 넘긴 인자에 따라 달라질 수 있어요. 서로 다른 행 타입이 반환될 수 있다면, 그 함수는 다형성 테이블 함수(polymorphic table function)예요.

다형성 테이블 함수를 이용하면 SQL 쿼리 안에서 커스텀 로직을 동적으로 호출할 수 있어요. 외부 시스템을 다루거나 SQL 표준을 넘어서는 기능으로 Trino를 확장할 때 유용해요.

Trino에 포함된 내장 테이블 함수 목록과, 커넥터가 전용 인터페이스를 구현해 커스텀 테이블 함수를 추가하는 방법도 지원돼요. 커넥터별로 지원하는 테이블 함수는 달라지므로, 상세한 내용은 각 커넥터 문서를 참고하세요.

내장 테이블 함수 (Built-in table functions)

exclude_columns 테이블 함수

입력 테이블 table에서 descriptor에 지정된 컬럼을 모두 제외한 새 테이블을 반환해요.

exclude_columns(input => table, columns => descriptor) → table

input 인자는 테이블 또는 쿼리이고, columns 인자는 타입이 없는 디스크립터(descriptor)예요.

TPC-H 커넥터가 제공하는 TPC-H 데이터셋의 orders 테이블을 사용한 예시에요.

SELECT *
FROM TABLE(exclude_columns(
                        input => TABLE(orders),
                        columns => DESCRIPTOR(clerk, comment)));

컬럼이 많은 테이블에서 거의 모든 컬럼을 반환하고 싶을 때 유용해요. 전체 컬럼을 나열하는 대신 제외할 컬럼만 지정하면 되거든요.

sequence 테이블 함수

sequential_number라는 단일 bigint 컬럼을 가진 테이블을 반환해요.

sequence(start => bigint, stop => bigint, step => bigint) -> table(sequential_number bigint)
  • start는 수열의 첫 번째 요소예요. 기본값은 0이에요.
  • stop은 범위의 끝(포함)이에요. 수열의 마지막 요소는 stop과 같거나, step으로 도달할 수 있는 범위 안의 마지막 값이에요.
  • step은 이후 값들 사이의 차이예요. 기본값은 1이에요.

예시 쿼리:

SELECT *
FROM TABLE(sequence(
                start => 1000000,
                stop => -2000000,
                step => -3));

sequence 테이블 함수의 결과는 정렬되지 않을 수 있어요. 정렬이 필요하면 쿼리에서 정렬을 강제하면 돼요.

SELECT *
FROM TABLE(sequence(
                start => 0,
                stop => 100,
                step => 5))
ORDER BY sequential_number;

테이블 함수 호출 (Table function invocation)

테이블 함수는 쿼리의 FROM 절에서 호출해요. 호출 문법은 스칼라 함수 호출과 비슷해요.

함수 해석 (Function resolution)

모든 테이블 함수는 카탈로그에서 제공되며, 카탈로그 안의 스키마에 속해요. 함수 이름에 스키마 이름, 또는 카탈로그와 스키마 이름을 붙여서 한정(qualify)할 수 있어요.

SELECT * FROM TABLE(schema_name.my_function(1, 100))
SELECT * FROM TABLE(catalog_name.schema_name.my_function(1, 100))

그 외에는 표준 Trino 이름 해석 규칙이 적용돼요. 함수는 해당 커넥터가 실행하므로 함수와 카탈로그 사이의 연결이 식별돼야 해요. 지정된 카탈로그가 함수를 등록하지 않았다면 쿼리는 실패해요. 테이블 함수 이름은 Trino의 스칼라 함수·테이블 해석과 마찬가지로 대소문자를 구분하지 않고 해석돼요.

인자 (Arguments)

인자에는 세 가지 타입이 있어요.

  • 스칼라 인자 (Scalar arguments): 상수 표현식이어야 하며, 선언된 인자 타입과 호환되는 모든 SQL 타입을 쓸 수 있어요.

    factor => 42
    
  • 디스크립터 인자 (Descriptor arguments): 이름과 선택적 데이터 타입을 가진 필드로 구성돼요.

    schema => DESCRIPTOR(id BIGINT, name VARCHAR)
    columns => DESCRIPTOR(date, status, comment)
    

    디스크립터에 null을 넘기려면 다음과 같이 해요.

    schema => CAST(null AS DESCRIPTOR)
    
  • 테이블 인자 (Table arguments): 테이블 이름이나 쿼리를 넘길 수 있어요. TABLE 키워드를 사용해요.

    input => TABLE(orders)
    data => TABLE(SELECT * FROM region, nation WHERE region.regionkey = nation.regionkey)
    

테이블 인자가 집합 의미론(set semantics)으로 선언되어 있으면 파티셔닝과 정렬을 지정할 수 있어요. 각 파티션은 테이블 함수에 의해 독립적으로 처리돼요. 파티셔닝을 지정하지 않으면 인자는 단일 파티션으로 처리돼요. 또한 PRUNE WHEN EMPTYKEEP WHEN EMPTY를 지정할 수 있어요. PRUNE WHEN EMPTY는 인자가 비어 있을 때 함수 결과에 관심이 없다는 뜻이고, Trino 엔진이 쿼리를 최적화하는 데 이 정보를 사용해요. KEEP WHEN EMPTY는 테이블 인자가 비어 있어도 함수를 실행해야 한다는 뜻이에요. 이 옵션을 지정하면 함수 작성자가 정한 속성을 덮어써요.

다음 예시는 테이블 인자 속성의 순서를 보여줘요.

input => TABLE(orders)
                    PARTITION BY orderstatus
                    KEEP WHEN EMPTY
                    ORDER BY orderdate

인자 전달 규칙 (Argument passing conventions)

테이블 함수에 인자를 전달하는 방법에는 두 가지가 있어요.

  • 이름으로 전달 (by name): 인자를 임의의 순서로 전달할 수 있어요. 기본값이 선언된 인자는 생략할 수 있죠. 인자 이름은 대소문자를 구분하며, 따옴표 없는 이름은 자동으로 대문자화돼요.

    SELECT * FROM TABLE(my_function(row_count => 100, column_count => 1))
    
  • 위치로 전달 (positionally): 인자가 선언된 순서를 따라야 해요. 생략되는 모든 인자가 기본값 선언된 경우에 한해, 인자 목록의 끝부분을 생략할 수 있어요.

    SELECT * FROM TABLE(my_function(1, 100))
    

한 번의 호출에서 두 규칙을 섞을 수는 없어요. 인자에 파라미터를 사용할 수도 있어요.

PREPARE stmt FROM
SELECT * FROM TABLE(my_function(row_count => ? + 1, column_count => ?));

EXECUTE stmt USING 100, 1;

더 알아보기 (Learn more)

테이블 함수로 쿼리 안에서 테이블을 동적으로 다룰 수 있게 됐어요. 이어서 Teradata SQL 호환 함수를 살펴보면 좋아요.