ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • SAP HANA SQLScript - 8장 명령형 로직 (8.1~8.3)
    SAP 2026. 5. 30. 20:54

    sqlscript_ch8_1to8_3.html
    0.03MB

     

     

    SAP HANA SQLScript - 8장 명령형 로직 (8.1~8.3)

    📘 SAP HANA SQLScript Reference
    Chapter 8 — Imperative SQLScript Logic (8.1 ~ 8.3)

    SAP HANA SQLScript Reference for SAP HANA Platform | pp. 112~140 정리

    1. 8장 개요 — Imperative SQLScript Logic

    이 장은 반복문(loop)과 조건문(conditional) 같은 명령형 언어 구성요소를 다룬다. 명령형 로직은 데이터 흐름을 여러 개로 분할하므로, 선언형 로직에 비해 성능이 떨어질 수 있다. 필요한 경우에만 선택적으로 사용하는 것이 권장된다.
    💡 관련 섹션 Declarative SQLScript Logic → p.88 참조

    2. 8.1 Scalar Variables (스칼라 변수)

    문법 (Syntax)

    DECLARE <sql_identifier> [{,<sql_identifier>}...] [CONSTANT] <type> | AUTO [NOT NULL] <proc_default> <proc_default> ::= (DEFAULT | '=') <value> | <expression> <value> !!= An element of the type specified by <type>

    핵심 설명

    • 로컬 변수는 DECLARE 키워드로 선언하며, 초기값을 함께 지정할 수 있다.
    • 기본값은 NULL로 초기화된다.
    • 변수 참조 시에는 :var 형식, 대입 시에는 var 형식을 사용한다.
    • 대입 연산자는 =을 권장한다 (:=도 지원되지만 SAP 권장사항이 아님).
    • 변수명은 영숫자, #, $, _를 지원하며, 대소문자 구분 이름도 가능하다.
    💡 Tip 변수 값 읽기:var, 변수에 값 대입var를 사용한다.
    ℹ️ Note — 대소문자 처리 더블쿼트 없는 SQL 식별자는 서버에서 대문자로 변환된다. 예: DECLARE myvar INT → 내부적으로 MYVAR로 처리. 대소문자를 유지하려면 더블쿼트 필수: DECLARE "MyVar" INT

    예제

    CREATE PROCEDURE proc (OUT z INT) LANGUAGE SQLSCRIPT READS SQL DATA
    AS
    BEGIN
        DECLARE a int;
        DECLARE b int = 0;
        DECLARE c int DEFAULT 0;
    
        t = select * from baseTable;
        select count(*) into a from :t;
        b = :a + 1;
        z = :b + :c;
    end;
    -- 스칼라 UDF 결과를 변수에 대입 (1 출력)
    DECLARE i INTEGER DEFAULT 0;
    SELECT SUDF_ADD(:input1, :input2) into i from dummy;
    
    -- 스칼라 UDF 다중 출력 변수 대입
    DECLARE i INTEGER DEFAULT 0;
    DECLARE j NVARCHAR(5);
    (i,j) = SUDF_EXPR(:input1);
    
    -- 대소문자 구분 변수 참조
    DO BEGIN
      DECLARE myvar INT = 0;
      DECLARE "MyVar" INT = 1;
      SELECT
        :myvar,       /* MYVAR - 첫 번째 변수 */
        :"MyVar"      /* MyVar - 두 번째 변수 */
      from dummy;
    END;

    2-1. 8.1.1 SELECT INTO with DEFAULT Values

    SELECT INTO는 결과셋을 스칼라 변수에 할당하는 데 널리 사용된다. 결과가 빈 셋(empty result set)인 경우 기존에는 exit handler가 필요했지만, DEFAULT 절을 사용하면 exit handler 없이 기본값을 적용할 수 있다.

    문법

    SELECT <select_list> INTO <var_name_list> [DEFAULT <scalar_expr_list>] <from_clause> [<where_clause>] [<group_by_clause>] [<having_clause>] [<order_by_clause>] [<limit>]; [EXEC | EXECUTE IMMEDIATE] <string_expression> [ INTO <var_name_list> [DEFAULT <scalar_expr_list>] ] [ USING <scalar_expr_list> ] -- 배열 인덱스를 이용한 INTO도 지원 <var_name> ::= <identifier> | <identifier> '[' <index> ']'

    예제 — 배열 인덱스 INTO

    DROP TABLE T1;
    CREATE TABLE T1 (A INT NOT NULL, B VARCHAR(10));
    
    DO BEGIN
        DECLARE A_COPY INT ARRAY;
        DECLARE B_COPY VARCHAR(10) ARRAY;
    
        -- 빈 결과 시 DEFAULT 적용: A_COPY[1]=-2+1=-1, B_COPY[1]=NULL
        SELECT A, B INTO A_COPY[1], B_COPY[1] DEFAULT -2+1, NULL FROM T1;
        SELECT :A_COPY[1], :B_COPY[1] from dummy;  -- (-1, ?)
    
        -- EXEC INTO에 DEFAULT 적용
        EXEC 'SELECT A FROM T1' INTO A_COPY[1] DEFAULT 2;
        SELECT :A_COPY[1], :B_COPY[1] from dummy;  -- (2, ?)
    
        INSERT INTO T1 VALUES (0, 'sample0');
        SELECT A, B INTO A_COPY[1], B_COPY[1] DEFAULT 5, NULL FROM T1;
        SELECT :A_COPY[1], :B_COPY[1] from dummy;  -- (0, 'sample0') 실제값 사용
    END;

    2-2. 8.1.2 SQL in Scalar Expressions

    SQLScript에서 SELECT를 스칼라 표현식 내의 서브쿼리로 사용할 수 있다. 단, 결과셋이 정확히 1행 × 1열이어야 한다.

    • 스칼라 값 대입의 서브쿼리로 사용 가능
    • 조건식의 서브쿼리로 사용 가능
    -- 스칼라 대입
    x = (SELECT TOP 1 val from mytab) * 10;
    
    -- 조건식 내 사용
    IF (SELECT MAX(val) FROM mytab) > 100 THEN ...
    
    -- 결과가 0건이면 null 반환
    create table empty_tab(i int);
    do begin
      declare n int = (select * from empty_tab) + 1; -- n = null
    end;
    ⚠️ 주의사항 결과가 2열 이상이면 ERR-00269 (too many values), 2행 이상이면 ERR-01300 (too many rows) 오류 발생.
    우변 전체가 SELECT 문으로만 구성된 경우 (x = SELECT * FROM tab) 테이블 변수 대입으로 처리됨 — 스칼라로 쓰려면 SELECT INTO를 사용할 것.
    ⚠️ 제한 (Limitation) AUTO 타입에는 서브쿼리를 사용할 수 없다.
    declare n auto = (select 10 from dummy) + 1; -- ERR-00007

    3. 8.2 Table Variables (테이블 변수)

    테이블 변수는 표 형식 데이터 구조를 참조하는 변수이다. 테이블 파라미터도 동일한 규칙이 적용된다. 관련 내용: Table Variable Type Definition → p.93

    3-1. 8.2.1 Table Variable Operators

    8.2.1.1 Index-Based Cell Access (인덱스 기반 셀 접근)

    테이블 변수의 특정 셀에 직접 읽기/쓰기 접근이 가능하다.

    <table_variable>.<column_name>[<index>]
    구분구문설명
    쓰기intab.A[2] = 5;2번 행의 A 컬럼에 값 5 쓰기
    읽기outvar = :intab.B[100];100번 행의 B 컬럼 값 읽기 (읽기 시 콜론 : 필요)
    ℹ️ 제한사항
    • 물리 테이블에는 접근 불가
    • SELECT :MY_TABLE_VAR.COL[55] AS A FROM DUMMY 형태는 지원 안 됨 — 먼저 스칼라 변수에 할당할 것
    • 인덱스 범위: 1 ~ 2^31-2 (2,147,483,646)
    create procedure procTCA (
        IN intab TABLE(A INTEGER, B VARCHAR(20)),
        OUT outtab TABLE(A INTEGER, B VARCHAR(20))
    )
    AS BEGIN
        intab.A[2] = 5;              -- 2행의 A 컬럼 수정
        outtab = select * from :intab;
    END;
    
    -- 읽기 예시
    create procedure procTCA (
        IN intab TABLE(A INTEGER, B VARCHAR(20)),
        OUT outvar VARCHAR(20)
    )
    AS BEGIN
        outvar = :intab.B[100];      -- 100행의 B 컬럼 읽기
    END;

    8.2.1.2 Modifying the Content of Table Variables

    SQL 레이어를 거치지 않고 테이블 변수의 내용을 직접 수정할 수 있어 성능이 향상된다. 단, 데이터 구체화(materialization)가 필요하므로 선언형 로직과 달리 메모리를 사용한다.

    ℹ️ Note 모든 위치 인덱스의 유효 범위: 1 ~ 2^31-1

    ▸ Inserting Data Records

    -- 전체 컬럼 삽입 (index 지정 시 해당 위치에 삽입, 생략 시 맨 끝에 추가) :<table_variable>.INSERT((<value1>, ..., <valueN>) [, <index>]) -- 일부 컬럼만 삽입 (생략 컬럼은 NULL) :<table_variable>.(<col1>, ..., <colN>).INSERT((<val1>, ..., <valN>) [, <index>]) -- 다른 테이블 변수 삽입 :<target>[.(<col_list>)].INSERT(:<source_table_var> [, <position>])
    -- 기본 사용 예시
    :OT.INSERT(('Section ' || K, VSUM), IDX);
    
    -- 일부 컬럼만
    :tab_a.(col1, COL2).insert(:tab_b);
    
    -- 다른 테이블 변수 삽입 - 컬럼 순서 매핑 주의
    -- SOURCE_TAB(X,A,B,C), TARGET_TAB(A,B,C,D)
    -- :target_tab.insert(:source_tab)  → X→A, A→B, B→C, C→D
    -- :TARGET_TAB.(D, A, B, C).insert(:SOURCE_TAB) → X→D, A→A, B→B, C→C

    ▸ Updating Data Records

    -- 전체 컬럼 업데이트 (index 필수) :<table_variable>.UPDATE((<val1>, ..., <valN>), <index>) <table_variable>[<index>] = (<val1>, ..., <valN>) -- 일부 컬럼만 (생략 컬럼은 변경 없음) :<table_variable>.(<col1>, ..., <colN>).UPDATE((<val1>, ..., <valN>), <index>) <table_variable>.(<col1>, ..., <colN>)[<index>] = (<val1>, ..., <valN>)
    ℹ️ Note 원래 테이블 크기를 벗어난 위치에도 값 설정 가능. INSERT처럼 중간 레코드는 NULL로 채워진다.

    ▸ Deleting Data Records

    구문동작
    :<table_variable>.DELETE([ <index> ])index 지정 시 해당 행 삭제, 생략 시 전체 삭제
    :<table_variable>.DELETE(<start>..<end>)범위 삭제 (start~end 행)
    :<table_variable>.DELETE(<array_of_integers>)인덱스 배열로 선택 삭제
    ℹ️ Note
    • index가 테이블 크기보다 크면 아무 동작도 하지 않음
    • end index < start index이면 오류 발생
    • 배열 삭제 시 배열에 잘못된 인덱스(예: 0)가 있으면 오류 발생
    -- 계층 구조 탐색 예 (DELETE 활용)
    CREATE PROCEDURE CALC_LEVEL (IN IT HIER, IN ROOT VARCHAR(30),
                                  OUT OT_LEVEL TABLE(NODE VARCHAR(30), L INT)) AS
    BEGIN
        DECLARE STACK TABLE(NODE VARCHAR(30), L INT);
        STACK[1] = (ROOT, 1);
    
        WHILE NOT IS_EMPTY(:STACK) DO
            DECLARE CURR_NODE VARCHAR(30) = :STACK.NODE[1];
            DECLARE CURR_LEVEL INT = :STACK.L[1];
            CHILDREN = SELECT CHILD FROM :IT WHERE PARENT = CURR_NODE;
            :OT_LEVEL.INSERT((CURR_NODE, CURR_LEVEL));
            :STACK.DELETE(1);   -- 스택 팝
            FOR I IN 1..RECORD_COUNT(:CHILDREN) DO
                :STACK.INSERT((:CHILDREN.CHILD[I], CURR_LEVEL + 1));
            END FOR;
        END WHILE;
    END;

    8.2.1.3 UNNEST Function

    하나 이상의 배열 및/또는 테이블 변수를 결합해 테이블로 변환한다. 결과는 반드시 테이블 변수에 대입해야 한다.

    <variable_name> = UNNEST(<unnest_param> [{, <unnest_param>}]) [WITH ORDINALITY] [AS (<column_specifier> [{, <column_specifier>}]) ] <unnest_param> ::= :table_variable | :array_variable | :array_function <column_specifier> ::= '*' | '(' <projection_aliasing_list> ')' | <column_name>
    -- 기본 사용
    CREATE PROCEDURE ARRAY_UNNEST_SIMPLE(OUT rst TABLE(":ARR_ID" INT, ":ARR_NAME" NVARCHAR(10)))
    READS SQL DATA
    AS BEGIN
        DECLARE arr_id INTEGER ARRAY = ARRAY(1, 2);
        DECLARE arr_name NVARCHAR(10) ARRAY = ARRAY('name1', 'name2', 'name3');
        rst = UNNEST(:arr_id, :arr_name);
        -- 결과: {1,name1}, {2,name2}, {?,name3}  ← 짧은 쪽은 NULL
    END;
    
    -- AS 절로 컬럼명 변경
    rst = UNNEST(:arr_id, :arr_name) AS (ID, NAME);
    
    -- WITH ORDINALITY (순서 컬럼 추가)
    CREATE PROCEDURE ARRAY_UNNEST(OUT rst TABLE(AMOUNT INTEGER, SEQ INTEGER))
    LANGUAGE SQLSCRIPT READS SQL DATA AS
    BEGIN
        DECLARE amount INTEGER ARRAY = ARRAY(10, 20);
        rst = UNNEST(:amount) WITH ORDINALITY AS ("AMOUNT", "SEQ");
        -- 결과: {10,1}, {20,2}
    END;
    
    -- 테이블 변수 UNNEST (projection aliasing)
    t0 = select * from tab0 order by a asc;
    t1 = select * from tab0 order by a desc;
    lt = unnest(:t0, :t1) as (*, (a as b));
    -- t0의 모든 컬럼(*) + t1의 a 컬럼을 b로 리네임
    ℹ️ Default Column Names 컬럼 지정자 없으면 자동 생성: COL1, COL2, ... / 중복 시 COL3→COL4 순으로 번호 증가. 순서 컬럼은 기본적으로 "ORDINALITY", 이미 존재하면 "ORDINALITY1", "ORDINALITY2" ...
    ResultLHS TypeRHS Type
    Potential run-time errorNOT NULLNOT NULL
    Compile-time errorNOT NULLNullable
    No errorNullableNOT NULL
    No errorNullableNullable
    ℹ️ Note Array 타입은 항상 nullable이다.

    8.2.1.4 IS_EMPTY — 빈 테이블 확인

    IS_EMPTY( <table_name> | <table_variable> )

    테이블 또는 테이블 변수가 비어 있으면 true, 아니면 false를 반환한다. IF문, WHILE 루프, 스칼라 대입에서 사용 가능.

    ⚠️ 주의 IS_EMPTY는 SQL 쿼리나 표현식 내에서는 직접 사용할 수 없다.
    CREATE PROCEDURE PROC_IS_EMPTY (IN tabvar TABLE(ID INTEGER),
                                      OUT outtab TABLE(ID INTEGER))
    AS BEGIN
        IF IS_EMPTY(:tabvar) THEN
            RETURN;
        END IF;
        CALL INTERNAL_LOGIC (:tabvar, outtab);
    END;

    8.2.1.5 RECORD_COUNT — 레코드 수 조회

    RECORD_COUNT( <table_name> | <table_variable> )

    테이블 또는 테이블 변수의 레코드 수를 BIGINT로 반환한다. IF문, 루프, 스칼라 대입 등 표현식이 허용되는 모든 곳에서 사용 가능.

    ⚠️ 주의 RECORD_COUNT는 SQL 쿼리(SELECT 등)에서는 사용할 수 없다.
    DO (IN inTab TABLE(col_a int) => TAB, OUT v INT => ?)
    BEGIN
        DECLARE i int;
        v = 0;
        FOR i IN 1 .. RECORD_COUNT(:inTab) DO
            v = :v + :inTab.col_a[:i];
        END FOR;
    END

    8.2.1.6 Search in Table Variables — 키 검색

    position = <tabvar>.SEARCH((<column_list>), (<value_list>) [, <start_position>])

    테이블 변수에서 키-값 쌍으로 효율적인 검색을 수행한다. 컬럼 목록과 값 목록의 크기가 같아야 한다. start_position 기본값은 1 (전체 스캔). 일치하는 첫 번째 레코드 위치를 반환하고, 없으면 NULL을 반환한다.

    ℹ️ Note SEARCH 함수는 다른 표현식과 함께 사용할 수 있지만, SQL 문 안에서는 직접 사용 불가.
    -- SEARCH + DELETE + 인덱스 접근 조합 예
    DECLARE LT1 TABLE ("Key1"..., "Key2"..., "Val1"...);
    -- LT1 = ... (초기 상태 참조)
    pos = :LT1.SEARCH(("Key1", "Key2"), ('I', 3));   -- pos = NULL (없음)
    :LT1.INSERT(('I', 3, 'X'), 0);                    -- 삽입
    pos = :LT1.SEARCH(("Key1", "Key2"), ('M', 3));   -- pos = 5
    :LT1.DELETE(pos);
    val = :LT1."Val1"[:LT1.SEARCH(("Key1", "Key2"), ('E', 5))];  -- val = 'V12'

    3-2. 8.2.2 SQL DML Statements on Table Variables

    SQLScript 테이블 변수에 SQL DML 문(INSERT, UPDATE, DELETE)을 직접 사용할 수 있다. 영구 테이블과 문법이 동일하지만, 테이블 변수는 앞에 콜론(:)을 붙여야 한다.

    DECLARE lt TABLE (a INT, b VARCHAR(20));
    INSERT INTO :lt VALUES (1, 'abc');
    UPDATE :lt SET b = 'def' WHERE a = 1;
    DELETE FROM :lt WHERE a = 1;

    지원되는 제약 조건

    • Primary Key 체크
    • NOT NULL 체크
    CREATE TYPE tt AS TABLE (a INT PRIMARY KEY, b INT NOT NULL);
    DECLARE lt1 tt;    -- 타입 정의의 제약 적용
    DECLARE lt2 TABLE (a INT, b INT, c INT NOT NULL, PRIMARY KEY(a, b));

    다른 구문과의 호환성 (Compatibility)

    DML 문으로 조작된 테이블 변수는 SQL 문에서만 사용 가능하다. 아래 표를 참고한다.

    구문DML 조작 후 사용 가능 여부
    SELECT * FROM :lt2✅ 가능
    INSERT INTO :lt2 (SELECT * FROM :lt1)✅ 가능
    CALL nested_proc(:lt2) (파라미터가 IN인 경우)✅ 가능
    :lt1.INSERT(:lt2) (INSERT 연산자)❌ 불가
    lt2 = SELECT * FROM :lt1 (대입 타겟)❌ 불가
    💡 DML과 비-DML 변수 간 변환 (Conversion) DML 구문과 비-DML 구문을 함께 써야 하면, 두 개의 테이블 변수를 사용해 서로 변환한다.
    DECLARE tab_without_dml TABLE (a INT);
    DECLARE tab_with_dml TABLE LIKE :tab_without_dml;
    
    tab_without_dml = SELECT * FROM mytab;           -- 비-DML 변수에 할당
    
    -- 비-DML → DML 변환 (데이터 복사)
    INSERT INTO :tab_with_dml (SELECT * FROM :tab_without_dml);
    -- DML 작업 수행
    DELETE FROM :tab_with_dml WHERE a > 100;
    
    -- DML → 비-DML 변환 (데이터 복사)
    tab_without_dml = SELECT * FROM :tab_with_dml;

    사용 권장 시나리오

    상황권장 방법
    복잡한 WHERE 조건의 UPDATE/DELETEDML 문 사용
    복잡한 UPDATE 구문DML 문 사용
    제약 조건 체크 필요DML 문 사용
    일반적인 데이터 조작SQLScript 테이블 변수 연산자 권장 (더 나은 성능)
    ⚠️ 제한 (Limitations)
    • 자율 트랜잭션(autonomous transaction)에서는 사용 불가
    • 병렬 실행 블록(parallel execution block)에서는 사용 불가
    • 프로시저/함수의 INPUT/OUTPUT 파라미터는 DML 문으로 조작 불가

    3-3. 8.2.3 Sorted Table Variables (정렬 테이블 변수)

    정렬 테이블 변수는 데이터 레코드를 검색 키(search key)에 의해 항상 정렬 상태로 유지하는 특수한 테이블 변수이다. 대량 데이터에 대한 명령형 알고리즘에서 효율적인 접근을 제공하며, SEARCH 연산자 사용 시 이진 탐색(binary search)이 적용된다.

    선언 문법

    -- 타입 정의에서 검색 키 지정 CREATE TYPE <name> AS TABLE (<column list>) SQLSCRIPT SEARCH KEY(<key list>) -- 변수 선언에서 검색 키 지정 DECLARE <name> TABLE(<column list>) SEARCH KEY(<key list>) DECLARE <name> <table type> SEARCH KEY(<key list>) -- 프로시저/함수 파라미터 CREATE PROCEDURE <proc> (IN <param> TABLE(<column list>) SEARCH KEY(<key list>))

    검색 키(Search Key) 동작 방식

    Search statement동작
    :LT.SEARCH(B, 1)B 컬럼으로 탐색. 이진 탐색 적용 → 1번 레코드 반환
    :LT.SEARCH((B, A), (1, 2))B, A 컬럼으로 탐색. 이진 탐색 적용 → 2번 레코드 반환
    :LT.SEARCH((B, C), (1, 15))B=1로 이진 탐색 후 C=15 순차 스캔 → 2번 레코드 반환
    :LT.SEARCH(A, 1)첫 번째 키 컬럼 B 없음 → 이진 탐색 불가, 순차 탐색 → 3번 레코드

    Output of Search Operator (전체 키 지정 시 특별 동작)

    검색 구문결과
    :LT.SEARCH(B, 3)전체 키 미지정 → 불일치 시 NULL 반환
    :LT.SEARCH((B, A, C), (1, 2, 20))전체 키 지정 → 불일치 시 음수 반환 (-3: B=1,A=2,C=20인 레코드가 삽입될 위치)
    💡 음수 반환값 활용 검색 후 음수 반환 시 해당 위치의 절댓값(-값)에 삽입하면 정렬 순서가 유지된다. 별도 위치 탐색 없이 직접 삽입 가능.

    동일 키 값을 가진 레코드 순회

    DECLARE pos int;
    DECLARE mytab TABLE (key1 int, key2 int, key3 int, value int) SEARCH KEY(key1, key2, key3);
    DECLARE keyval1, keyval2 int;
    ...
    -- 처음 두 키 컬럼이 특정 값인 레코드 순회
    pos = :mytab.SEARCH((key1, key2), (keyval1, keyval2));
    IF pos > 0 THEN
        WHILE :mytab.key1[pos] = keyval1 AND :mytab.key2[pos] = keyval2 DO
            -- pos 위치의 레코드 처리
            pos = pos + 1;
        END WHILE;
    END IF;

    정렬 테이블 변수 수정 연산자 규칙

    연산동작 규칙
    INSERT (위치 미지정)정렬 순서를 유지하는 올바른 위치에 삽입
    INSERT (위치 지정)정렬 위반 여부 확인 → 위반 시 오류 발생
    UPDATE / 셀 대입검색 키 컬럼 수정 불가 / 존재하지 않는 레코드 수정 불가
    Primary Key정의된 경우 모든 연산에서 유일성 검사

    제한 사항 (Limitations)

    • 검색 키에 지원되지 않는 타입: Spatial data types, LOB types
    • 테이블 함수(Table Function)의 출력은 정렬 테이블 타입으로 정의 불가

    4. 8.3 Auto Type Derivation (자동 타입 추론)

    변수의 타입을 명시하지 않고 SQLScript가 자동으로 타입을 결정하도록 하는 기능. 스칼라 변수, 테이블 변수, 배열에 모두 사용 가능하다.

    문법 (Syntax)

    -- 스칼라 AUTO 변수 DECLARE <sql_identifier> [{, <sql_identifier>}...] [CONSTANT] AUTO [NOT NULL] <proc_default> -- 테이블 AUTO 변수 DECLARE <sql_identifier> [{, <sql_identifier>}...] [CONSTANT] AUTO <proc_table_default>
    ⚠️ 주의 DEFAULT 값은 필수이며 생략할 수 없다.

    예제

    declare var1 auto = 1.0;                         -- DECIMAL 타입으로 추론
    declare arr1 auto = array(1, 2);                 -- INTEGER ARRAY로 추론
    declare tab1 auto = select 1 as x from dummy;    -- TABLE(x INT)로 추론

    타입 추론 규칙 (Data Type Derivation)

    기본값의 타입을 기반으로 추론되지만, 길이가 있는 경우 최대 길이(MAX_LENGTH)를 사용한다.

    실제 기본값 타입추론되는 AUTO 변수 타입
    VARCHAR(n)VARCHAR(MAX_LENGTH)
    NVARCHAR(n)NVARCHAR(MAX_LENGTH)
    ALHPANUM(n)ALPHANUM(MAX_LENGTH)
    VARBINARY(n)VARBINARY(MAX_LENGTH)
    DECIMAL(p, s)DECIMAL
    SMALLDECIMALDECIMAL
    ⚠️ Caution — 비호환성 주의 AUTO가 키워드로 처리되므로, 기존에 AUTO라는 이름의 테이블/타입을 사용하던 코드에 문제가 발생할 수 있다.
    회피 방법: SCHEMA.AUTO 또는 "AUTO"(따옴표) 형식으로 사용.
    예시:
    -- 비호환 예시
    create table auto (a bigint);
    declare tab1 auto = select 1 a, 2 b from dummy; -- 오류!
    
    -- 회피 방법
    do begin
      declare tab1 "AUTO";         -- 따옴표 사용
      declare tab2 schema_x.auto;  -- schema.table_name 사용
    end;

    AUTO 타입 제한 사항 (Scope and Limitations)

    • 트리거(trigger) 내부에서는 사용 불가
    • Row-type 변수에는 사용 불가
    • 기본값이 다음을 포함하는 경우 사용 불가:
      • 시스템 변수 (system variables)
      • 테이블 또는 auto-type 테이블의 스칼라 접근
    #SAP_HANA #SQLScript #AMDP #ScalarVariables #TableVariables #SortedTableVariables #DECLARE #UNNEST #IS_EMPTY #RECORD_COUNT #AutoType #DML_TableVariable #SearchKey #BinarySearch #ImperativeLogic
Designed by Tistory.