PDH 개발 공부

[개발자를 위한 PL/SQL] 11장 - 컬렉션 본문

DataBase/PL-SQL

[개발자를 위한 PL/SQL] 11장 - 컬렉션

IFBB 2021. 6. 29. 17:18
  • PL/SQL 은 단일 값 데이터 타입 , 복합 데이터 타입 2가지를 지원을 한다.
  • 복합 데이터 타입으로 컬렉션과 레코드를 지원
  • 컬렉션은 동일한 데이터 타입을 반복되는 데이터를 저장하는 자료구조
  • 레코드는 서로 다른 데이터 타입의 데이터를 모아 놓은 자료구조

컬렉션 타입의 종류

  • Associative Array : 키와 값으로 구성된 Map
  • VARRAY : 선언할 때 크기(요소 개수)를 지정한 만큼 배열을 만든다. 일반적인 프로그래밍 언어에서 지원하는 배열(Array)에 해당함.
  • Nested Table : 연관 배열과 비슷한 모양이나, 인덱스가 모두 숫자로 되어있다. 연관배열과 가변배열을 합친 모습의 컬렉션이며 가변 배열과 비슷하게 제어할 수 있다.

예를 들어, for문을 통해 순회할 수 있으며 초기화도 비슷하게 이루어진다.

// REM VARRAY를 사용한 스키마 레벨 데이터 타입 정의
CREATE OR REPLACE TYPE languages IS VARRAY(10) OF VARCHAR2(64)


// REM Nested Table을 사용한 스키마 레벨 데이터 타입 정의
CREATE OR REPLACE TYPE cities IS TABLE OF VARCHAR2(64)

Associative Array 사용법

  • NULL이 될수 없다 (할당 시 오류 발생)
  • 정수와 문자열 둘중 하나 사용 가능
TYPE 타입명 IS TABLE OF 데이터타입 INDEX BY 인덱스데이터타입;
변수명 타입명 ;

후 변수를 선언해서 사용하면 된다.

예시 1)

DECLARE
  TYPE int_array IS TABLE OF PLS_INTEGER INDEX BY PLS_INTEGER; -- Associative Array ADT
  v_fibonacci int_array ; -- 피보나치 수열을 저장할 배열
  c_order CONSTANT PLS_INTEGER := 20 ;

  /*
   * N 개의 피보나치 수열을 계산하여 배열을 반환하는 함수
   * 피보나치 수열은 처음 두 개의 항이 0과 1이고, 세 번째 항부터는
   * F(n) = F(n-1) + F(n-2)의 점화식으로 주어지는 수열이다.
   */
  FUNCTION fibonacci_sequence(num IN PLS_INTEGER) RETURN int_array
  IS
    v_arr int_array; -- 반환할 피보나치 수열(Associative Array)
  BEGIN
    v_arr(1) := 0 ;      -- 첫 번째 항
    v_arr(2) := 1 ;      -- 2 번째 항
    FOR i IN 3..num LOOP -- 3번째 항 이상
      v_arr(i) := v_arr(i-1) + v_arr(i-2) ; 
    END LOOP;
    RETURN v_arr ; -- Associative Array를 반환
  END ;

BEGIN
  v_fibonacci := fibonacci_sequence(c_order) ; -- 함수가 반환한 Associative Array
  DBMS_OUTPUT.PUT_LINE('피보나치 수열의 '||c_order||'개 항') ;
  FOR i IN 1 .. c_order
  LOOP
    DBMS_OUTPUT.PUT(CASE WHEN 1 < i THEN ', ' END || v_fibonacci(i)) ;
  END LOOP ;
  DBMS_OUTPUT.PUT_LINE('') ;
END;

예시 2)

하나하나 할당 해주는 방법이 있지만 이런 방법도 있다.

REM BULK COLLECT를 사용하면 여러 건의 SELECT 결과를 
REM Associative Array 변수에 넣을 수 있다.
DECLARE
  TYPE string_array IS TABLE OF VARCHAR2(100) INDEX BY PLS_INTEGER;
  v_arr string_array ;
BEGIN
  -- 테이블 emp의 모든 로우의 ename을 Associative Array 컬렉션에 한 번에 적재한다.
  SELECT ename
    BULK COLLECT INTO v_arr
    FROM emp ;
  DBMS_OUTPUT.PUT_LINE('Associative Array 컬렉션 건수 = '||v_arr.COUNT) ;
END ;

VARRAY 사용법**

  • 인덱스는 1부터 시작하는 자연수 값
  • 초기화 되지 않는 변수는 NULL
TYPE 타입명 IS VARRAY(크기) OF 데이터타입;
변수명 타입명 ;

예시)1

DECLARE
  -- VARRAY 타입 선언 : 자연수를 인덱스로 하는, 최대 10개의 64바이트 문자열의 배열
  TYPE languages IS VARRAY(10) OF VARCHAR2(64);
  v_lang  languages ; -- VARRAY 변수 선언. v_lang = NULL임
  v_lang2 languages := languages('한국어', '중국어', '영어') ; -- 변수 선언 시 생성자를 사용하여 초기화
BEGIN
  v_lang := languages() ;                   -- 컬렉션 생성자를 사용하여 Empty(크기가 0)로 초기화.
  v_lang := languages('한국어') ;           -- 컬렉션 생성자를 사용하여 크기가 1인 VARRAY로 재초기화
  v_lang := languages('한국어', '중국어') ; -- 컬렉션 생성자를 사용하여 크기가 2인 VARRAY로 재초기화

  v_lang.EXTEND(2) ; -- 크기 두 개 증가
  v_lang(3) := '일본어' ;
  v_lang(4) := '영어' ;

  -- v_lang에 들어 있는 언어 출력
  DBMS_OUTPUT.PUT_LINE('    ') ;
  DBMS_OUTPUT.PUT_LINE('언어 목록') ;
  DBMS_OUTPUT.PUT_LINE('===========') ;
  FOR i in v_lang.FIRST .. v_lang.LAST
  LOOP
    DBMS_OUTPUT.PUT_LINE(TO_CHAR(i) || ' : ' ||v_lang(i)) ;
  END LOOP ;
END ;

예시2)

BULK COLLECT는 여러 건의 SELECT 결과를 VARRAY 변수에 넣는다

DECLARE
  TYPE string_array IS VARRAY(20) OF VARCHAR2(100) ;
  v_arr string_array ;
BEGIN
  -- 테이블 emp의 모든 로우의 ename을 VARRAY 컬렉션에 한 번에 적재한다.
  SELECT ename
    BULK COLLECT INTO v_arr
    FROM emp
   WHERE ROWNUM <= 20 ;
  DBMS_OUTPUT.PUT_LINE('VARRAY 컬렉션 건수 = '||v_arr.COUNT) ;
END ;

Nested Table 사용법

순서가 고정되어 있지 않고 크기도 고정되지 않는 데이터의 집합을 저장하는데 적합한 컬렉션

TYPE 타입명 IS TABLE OF 데이터타입 ;
변수명 타입명; 

예시)1


DECLARE
  -- 정수를 인덱스로 하는 Nested Table
  TYPE city IS TABLE OF VARCHAR2(64) ;

  -- 빈 컬렉션 변수 선언
  v_city       city ;

  -- 컬렉션 변수 선언과 동시에 컬렉션 생성자를 사용하여 값을 초기화
  v_city2      city := city('서울', '부산', '대전') ;
BEGIN
  -- 실행 중에도 컬렉션 생성자를 사용하여 초기화 가능
  v_city := city('서울', '부산', '대전', '광주', '인천') ;

  v_city := city() ;  -- 크기 0(Empty 컬렉션)으로 초기화
  -- 크기를 증가시키고, 값을 지정한다.
  v_city.EXTEND ; v_city(1) := '서울' ;
  v_city.EXTEND ; v_city(2) := '부산' ;
  v_city.EXTEND ; v_city(3) := '대구' ;
  v_city.EXTEND ; v_city(4) := '광주' ;
  DBMS_OUTPUT. PUT_LINE('도시 개수 : ' ||v_city.COUNT||'개') ;

  -- 유효한 컬렉션 값을 출력
  FOR i in v_city.FIRST .. v_city.LAST
  LOOP
    IF v_city.EXISTS(i) THEN
      DBMS_OUTPUT.PUT_LINE(CHR(9)||'v_city(' || TO_CHAR(i) || ') : ' ||v_city(i)) ;
    END IF ;
  END LOOP ;

  -- 3번 인덱스를 삭제한다. 삭제된 인덱스의 항목은 더 이상 접근이 불가능하다.
  v_city.DELETE(3) ;
  DBMS_OUTPUT. PUT_LINE('도시 개수 : ' ||v_city.COUNT||'개') ;

  -- 유효한 컬렉션 값을 출력
  FOR i in v_city.FIRST .. v_city.LAST
  LOOP
    IF v_city.EXISTS(i) THEN
      DBMS_OUTPUT.PUT_LINE(CHR(9)||'v_city(' || TO_CHAR(i) || ') : ' ||v_city(i)) ;
    END IF ;
  END LOOP ;
END ;

'DataBase > PL-SQL' 카테고리의 다른 글

[개발자를 위한 PL-SQL] 12장 - 레코드  (0) 2021.06.30
Comments