5. 진보적인 POSTGRES SQL 의 특징

이제 기본적인 데이터 관리와는 구별되는 POSTGRES 의 특징에 대해서 논의해 볼 것이다. 이러한 특징에는 상속, 시간 여행, 비원자화 데이터 값들 (array- 와 set-valued 속성) 등이 있다. 이장에서 나오는 예는 교재(tutorial) 디렉토리에 'advance.sql' 에 나와있다. (이것을 어떻게 사용하는 지는 앞장의 서론 부분을 참조하자.)

5.1 상속

두개의 클래스를 만들어 보자. 'capitals' 클래스는 하나의 도시, 주의 수도 를 포함한다. 자연스럽게, 'capitals' 클래스는 'cities' 로부터 상속받아야 한 다.

   CREATE TABLE cities (
            name        text,
            population  float,
            altitude    int            -- (in ft)
   );
 
   CREATE TABLE capitals (
            state       char2
   ) INHERITS (cities);

이 경우에, 'capitals' 의 인스턴스는 그의 부모로부터 모든 속성 ('name', 'population', 'altitude') 를 상속받는다. 속성 'name' 의 타입은 'text' 이다. 'text' 는 가변 길이의 아스키 문자열에 사용되는 POSTGRES 에 내장되어 있는 타입 이다. 속성 'population' 의 타입은 'float4' 이며, 이 타입은 더블 정밀도의 부동소수에 사용되는 POSTGRES 내장형이다. 주의 수도(state capitals)는 또다른 속성으로 주를 나타내는 'state' 를 가지고 있다. POSTGRES 에서, 하나의 클래 스는 0개 이상의 클래스로부터 상속받을 수 있고,(주4)하나의 질의는 어떤 클래스의 모든 인스턴스나 이것과 함께 인스턴스의 자손까지 참조할 수 있다. 예를 들면, 아래의 질의는 고도 500 피트 보다 높은 곳에 있는 도시를 검색하는 것이다.

주4) 상속체계는 바로 acyclic 그래프이다.

   SELECT name, altitude
   FROM cities
   WHERE altitude > 500;
 
 
   name     |altitude
   ---------+--------
   Las Vegas|    2174
   Mariposa |    1953
   (2 rows)

500 피트 이상에 있는 모든 도시를 주의 수도를 포함하여 찾고자 한다면, 해당 질의는 다음과 같다.

   SELECT c.name, c.altitude
   FROM cities* c
   WHERE c.altitude > 500;

결과는 다음과 같다.

   name     |altitude
   ---------+--------
   Las Vegas|    2174
   Mariposa |    1953
   Madison  |     845
   (3 rows)

'cities' 다음의 '*' 는 'cities' 와 'cities' 에서 상속받은 모든 클래스를 나타 낸다. 이미 앞에서 살펴본 많은 명령 - select, update, delete - 은 'alter' 명령과 유사한 이러한 '*' 표기를 제공한다.

5.2 시간 여행

POSTGRES 는 시간 여행에 대한 표기법을 지원한다. 이러한 특징은 사용자로 하여금 역사적인 질의를 할 수 있도록 한다. 예를 들면, Mariposa 도시의 현재의 인구를 검색하려면, 다음과 같이 사용할 수 있을 것이다.

   SELECT * FROM cities WHERE name = 'Mariposa';
 
 
   name    |population|altitude
   --------+----------+--------
   Mariposa|      1320|    1953
   (1 row)
 

POSTGRES 는 자동적으로 현재 싯점에서의 유효한 Mariposa 도시의 레코드를 찾을 것이다. 여기에서 시간범위를 부여할 수 있다. Mariposa 도시의 과거의 인구를 알아보려면,다음과 같이 질의하면 된다.

 
   SELECT name, population
   FROM cities['epoch', 'now']
   WHERE name = 'Mariposa';

'epoch' 는 시스템 시간의 시작싯점을 나타낸다. (주5) 지금까지의 모든 예제를 실행시켰다면, 질의의 결과는 다음과 같을 것이다.

주5) UNIX 시스템에서는, 이 싯점은 항상1970 GMT 1월 1일 00시이다.

   name    |population
   --------+----------
   Mariposa|      1200
   Mariposa|      1320
   (2 row)

시간범위에서 디폴트 시작지점은 시스템이 시간을 표시할 수 있는 최초의 시각이며, 디폴트 끝지점은 현재 시각이다. 따라서, 위의 시간범위는 "[,]." 와 같이 단축하여 사용할 수 있다.

5.3 원자화되지 않은 값

관계형 모델에서의 관계의 속성은 보통 원자화(atomic)된다는 것이다. POSTGRES 에는 이러한 제한이 없다. 속성은 질의어로 접근할 수 있는 보조값(sub-values) 을 가질 수 있다. 예를 들면, 하나의 속성을 기본 타입의 배열로 만들 수 있 다.

5.3.1 배열

POSTGRES 에서는 하나의 인스턴스의 속성은 고정길이 또는 가변길이의 다차원 배열 로 정의 될 수 있다. 어떠한 기본형이나 사용자 정의형의 배열도 만들 수 있다. 실례를 보이기 위해, 여기서는 먼저 기본형의 배열을 사용하여 클래스를 만들어 보 겠다.

   CREATE TABLE SAL_EMP (
          name             text,
          pay_by_quarter   int4[],
          schedule         char16[][]
   );
 

위의 질의는 SAL_EMP 로 불리우는 클래스를, text 문자열('name')과 int4의 1차원 배열('pay_by_quarter'), 그리고 char16 의 2차원 배열('schedule')의 구성으로 생성한다. 'pay_by_quarter' 는 사원들에게 지급되는 4등분된 급료이며, 'schedule' 는 사원들의 주간계획이다. 이제 데이터를 조금 삽입해보자. 배열에 데이터를 추가할 때는, 해당값은 중괄호 사이에 와야 하고, 콤마에 의해 구분된다.

C 를 알고 있다면, 구조체의 초기화 문법과 별로 다르지 않다는 것을 알 수 있을 것이다.

   INSERT INTO SAL_EMP
        VALUES ('Bill',
                '{10000, 10000, 10000, 10000}',
                '{{"meeting", "lunch"}, {}}');
 
   INSERT INTO SAL_EMP
        VALUES ('Carol',
                '{20000, 25000, 25000, 25000}',
                '{{"talk", "consult"}, {"meeting"}}');

POSTGRES 에서는 기본적으로 배열에서 번호를 붙일 때 1부터 시작한다. n 개의 원소를 가진 배열은 배열[1] 에서 시작하여 배열[n]으로 끝난다.

이제, SAL_EMP 에 몇개의 질의를 던져보자. 먼저, 어느 한 싯점에서 배열중 하나의 원소에 접근하는 방법을 알아보자. 다음의 질의는 사원들 중 급료의 두번째 배당금이 변경된 사람을 검색한다.

   SELECT name
   FROM SAL_EMP
   WHERE SAL_EMP.pay_by_quarter[1] <>
         SAL_EMP.pay_by_quarter[2];
 
   name 
   -----
   Carol
   (1 row)

다음의 질의는 모든 사원들의 급료중 세번째 배당금을 보여준다.

   SELECT SAL_EMP.pay_by_quarter[3] FROM SAL_EMP;
 
   pay_by_quarter
   --------------
            10000
            25000
   (2 rows)
 

POSTGRES 에서는 배열의 조각(slices), 또는 보조배열(subarrays)에 접근할 수 있다. 다음의 질의는 Bill 의 주간계획에서 처음 두번째날의 첫번째 아이템을 검색한다.

   SELECT SAL_EMP.schedule[1:2][1:1]
   FROM SAL_EMP
   WHERE SAL_EMP.name = 'Bill';
 
   schedule          
   ------------------
   {{"meeting"},{""}}
   (1 row)