상세 컨텐츠

본문 제목

SQL 예제로 배우는 PostgreSQL (ver 0.91a)

프로그래밍/DB

by 라제폰 2008. 12. 23. 08:49

본문

1. 들어가며

1.1 테스트 환경

이 문서의 테스트환경은 다음과 같다.

  • PostgreSQL 7.0.3
  • WOW Linux 6.2

1.2 참조 사이트

다음은 인터넷을 통해 "postgresql"과 관련된 자료를 참조할 수 있는 사이트들이다.

또한, 미흡한 필자의 홈페이지 http://ngd.pe.kr에서 관련 문서들을 참조할 수 있다.

1.3 당부의 말

현재 이문서에는 필자가 모르는 오타가 있을 것이고, 논리에 맞지않는 부분도 있을 것입니다. 이러한 부분에 대해 메일로 지적을 해 준다면 다음 수정판에 꼭 반영할 것입니다.

이글을 읽고서 기타 추가사항이 있다면 주저없이 메일로 보내주시면 고맙겠습니다.

끝으로 이글에 대한 질문들, 즉 SQL이나 포스트그레스 자체에 대한 질문들은 받지 않습니다.

 

2. 설치 및 기타사항

2.1 Source Install

포스트그레스는 ftp://ftp.postgresql.org/pub 에서 postgresql-7.0.3.tar.gz를 다운받고, root 유저로 설치한다. 다음은 압축을 푸는 예이다.

  $ cd /usr/local/src
  $ tar zxvf postgresql-7.0.3.tar.gz 

Configure , make , make install를 한다. 다음은 configure, make 및 make install 예이다.

  $ cd /usr/local/src/postgresql-7.0.3/src
  $ ./configure --enable-multibyte \ 
     --enable-locale \
     --with-tcl 
  $
  $ make
  $ make install
  $
  $ cd ../doc    
  $ make install
  $
  $ adduser postgres
  $ chown -R postgres:postgres /usr/local/pgsql 

환경 설정을 한다. 환경설정은 /etc/ld.so.conf 와 /etc/profile 만을 편집한다.

다음은 환경설정 예이다.

 $ vi /etc/ld.so.conf
   /usr/local/pgsql/lib  <=마지막 라인에 추가
 $
 $ /sbin/ldconfig
 $
 $ vi /etc/profile 
    ...
    ...
  PGDATA=/usr/local/pgsql/data
  PGLIB=/usr/local/pgsql/lib
  MANPATH=$MANPATH:/usr/local/pgsql/man
  PATH=$PATH:/usr/local/pgsql/bin

  export  PGDATA PGLIB MANPATH PATH 
 $
 $ . /etc/profile
 $

설치를 완료하면 첫 실행을 할 준비가 되었다. 다음은 실행 예이다.

 $ su - postgres
 $ initdb -E EUC_KR 
 $ pg_ctl start

2.2 initdb

initdb 는 포스트그레스의 데이타베이스들을 관리하기 위한 정보 및 데이타베이스를 저장할 디렉토리를 만들며, 포스트그레스가 기동되기전에 실행되어져야 한다. 기타 포스트그레스와 관련된 여러가지 초기화 작업을 한다.

initdb 는 환경변수 PGDATA 값을 참조하여 /pgsql_base_dir/data 디렉토리를 만들며 /pgsql_base_dir/data/base 디렉토리에 각 데이타베이스들이 저장된다.

참고로 포스트그레스의 initdb 실행 후 template1이라는 데이타베이스가 생성된다.

2.3 initlocation 예제

initlocation은 다른 PGDATA 를 정의할 수 있다. 즉 데이타베이스가 $PGDATA외의 다른 디렉토리에 저장될 수 있다. 다음은 initlocation의 활용 예 및 데이타베이스 생성 예이다.

 $ su - postgres
 $ export PGDTA2=/usr/local/pgsql/data2
 $ export PGDTA3=/usr/local/pgsql/data3
 $ export PGDTA4=/usr/local/pgsql/data4
 $ initlocation PGDATA2
 
 The location will be initialized with username "postgres".
 This user will own all the files and must also own the server process.

 Creating directory /usr/local/pgsql/data2
 Creating directory /usr/local/pgsql/data2/base

 initlocation is complete.
 You can now create a database using

   CREATE DATABASE <db_name> WITH LOCATION='PGDATA2';

 in SQL, 

   or

   createdb <db_name> -D 'PGDATA2'

 from thr shell.
 $
 $ initlocation PGDATA3
 
 The location will be initialized with username "postgres".
 This user will own all the files and must also own the server process.

 Creating directory /usr/local/pgsql/data3
 Creating directory /usr/local/pgsql/data3/base

 initlocation is complete.
 You can now create a database using

   CREATE DATABASE <db_name> WITH LOCATION='PGDATA3';

 in SQL, 

   or

   createdb <db_name> -D 'PGDATA3'

 from thr shell.
 $ 
 $ initlocation PGDATA4
 
 The location will be initialized with username "postgres".
 This user will own all the files and must also own the server process.

 Creating directory /usr/local/pgsql/data4
 Creating directory /usr/local/pgsql/data4/base

 initlocation is complete.
 You can now create a database using

   CREATE DATABASE <db_name> WITH LOCATION='PGDATA4';

 in SQL, 

   or

   createdb <db_name> -D 'PGDATA4'

 from thr shell.
 $
 $ pg_ctl start
 $
 $ createdb ngd_db1 -D 'PGDATA2'
  CREATE DATABASE
 $
 $ psql ngd_db1
  ...
  ngd_db1=# create database test_db with location='PGDATA2';
  CREATE DATABASE
  ngd_db1=# \q
 $ 
 $ psql test_db
  ..
  test_db=# \q
 $
 $ createdb ngd_db2 -D 'PGDATA3'
  CREATE DATABASE
 $
 $ psql ngd_db2
  ...
  ngd_db2=# \q
 $
 $ createdb ngd_db3 -D 'PGDATA4'
  CREATE DATABASE
 $
 $ psql ngd_db3
  ...
  ngd_db3=# \q
 $

2.4 template1

"template1" 데이타베이스는 포스트그레스의 "initdb"명령을 통해 제일 처음 생성되는 데이타베이스이다. 새로 생성되는 데이타베이스들을 위한 기본적인 틀(template) 역할을 한다.

다음의 예에서 $PGDATA 를 삭제한다. 만약 자신의 중요한 데이타를 가지고 있는 데이타베이스가 있다면 이 예는 그냥 눈으로만 보고 따라하지 말기를 바란다. -- 주의 요망

template1 은 처음 생성되는 데이타베이스에게 자신의 속성을 제공하여 상속케한다. 또한 template1이 소유한 테이블 중 사용자가 작성한 테이블이 있다면 이 또한 새로 생성되는 데이타베이스에 상속된다.

다음은 template1의 상속 예를 보여준다.

 $ su - postgres
 $ pg_ctl stop
 $ rm -rf /usr/local/pgsql/data
 $ export PGDATA2=/usr/local/pgsql/data2
 $ initdb -E EUC_KR
 $ initlocation PGDATA2

위의 과정을 거치면서 포스트그레스는 물리적으로 서로 다른 데이타베이스 저장소를 가진다. (PGDATA, PGDTA2)

 $ pg_ctl start

 $ createlang plpgsql template1
  CREATE LANGUAGE

 $ psql template1
  ...
  template1=# create table temp_tab (
     id_temp int4 ,
     name_temp text
  );
  CREATE
  template1=# \q
 $

 $ createdb ngd_db1
  CREATE DATABASE

 $ createdb ngd_db2 -D 'PGDATA2'
  CREATE DATABASE

 $ psql ngd_db1
  ...
  ngd_db1=# \d
        List of relations
     Name    |   Type   |  Owner
  -----------+----------+----------
   temp_tab  |   table  | postgres
  (1 row)
  
  ngd_db1=# select * from pg_database;
    lananem   |..| lancompiler
  ------------+--+--------------
    internal  |..| n/a
    C         |..| /bin/cc
    sql       |..| postgres
    plpgsql   |..| PL/pgSQL
    (4 rows)

  ngd_db1=# \q

$ psql ngd_db2
  ...
  ngd_db2=# \d
        List of relations
     Name    |   Type   |  Owner
  -----------+----------+----------
   temp_tab  |   table  | postgres
  (1 row)
  
  ngd_db2=# select * from pg_database;
    lananem   |..| lancompiler
  ------------+--+--------------
    internal  |..| n/a
    C         |..| /bin/cc
    sql       |..| postgres
    plpgsql   |..| PL/pgSQL
    (4 rows)

  ngd_db2=# \q
 $

2.5 pg_ctl

pg_ctl은 쉘 스크립트이며 포스트그레스의 실행,중지,재실행등을 하며 또한, 실행 상태등을 보여주는 유틸리티이다.

다음은 pg_ctl의 실행 예이다.

 $ su - postgres
 $ pg_ctl start 
 
 // 위의 라인은 포스트그레스를 실행한다. 

 $ su - postgres
 $ pg_ctl -w start 
 
 // 위의 라인은 포스트그레스를 실행하지만, 바로 실행하는 것이 아니라 
 // 정상적으로 실행할 때까지 일정시간 대기한다. 
 // "-w"는 "wait"를 의미한다. 

 
 // 다음은 "pg_ctl -w start' 한 후의 예이다. 
 
 $ pg_ctl -w start
 Waiting for postmaster starting up...DEBUG: Data Base System is 
 starting up at Tue Mar 20 01:01:50 2001
 DEBUG:  Data Base System was shut down at Thu Mar 15 19:29:15 2001
 DEBUG:  Data Base System is in production state at Tue Mar 20 01:01:50 2001
 done.
 postmaster successfully started up.
 $

 
 $ su - postgres
 $ pg_ctl restart
 // 위의 라인은 "pg_ctl"을 재실행한다. 

 $ su - postgres
 $ pg_ctl stop
 // 포스트그레스의 실행을 멈춘다.

 $ su - postgres
 $ pg_ctl status 
 //위의 라인은 "pg_ctl"의 실행 상태를 보여준다. 

 $ su - postgres
 $ pg_ctl status
  pg_ctl: postmaster is running (pid: 899)
  options are:
  /usr/local/pgsql/bin/postmaster
  -p 5432
  -D /usr/local/pgsql/data
  -B 64
  -b /usr/local/pgsql/bin/postgres
  -N 32
 $

다음은 pg_ctl status의 결과에 대한 설명이다.

  • -p 는 포트(port)를 의미한다.
  • -D 는 $PGDATA 를 의미한다.
  • -B 는 포스트그레스 프로세스가 사용하는 버퍼이다.
  • -N 은 동시에 실행할 수 있는 포스트그레스 프로세스의 최대개수.

$PGDATA는 일반적으로 "/usr/local/pgsql/data" 을 값으로 가진다. 이러한 $PGDATA 디렉토리에는 pg_ctl의 실행시간에 참조할 옵션들을 저장하는 파일이 있다.

바로 "postmaster.opts.default" 라는 파일이다. 이 파일에는 다음과 같은 옵션이 저장될 수 있다.

 -N 64 -B 256 -o '-F -S 1024'

위의 "-N" 은 동시에 실행될 프로세스의 최대개수를 정의하며 "-B" 는 각 포로세스들이 사용할 버퍼의 크기를 정의하며, 이 때 버퍼의 크기는 최소한 프로세스 최대개수의 두배이어야 한다.

-o 는 postgres 프로세스에 대한 옵션을 정의하며 "-F" 는 각각의 트랜잭션의 결과값을 저장하기 위한 fsync() 호출을 disable 한다. 즉, -F 는 Bool 의 값을 지닌다.

"-S" 는 "odrer by" 나 "join" 등의 sorting 을 할 때 사용하는 Sorting Buffer 의 크기를 정의한다. 이 때 소팅 버퍼의 크기가 작으면, 소팅 동작중 정의된 버퍼보다 많은 크기를 요구 한다면 디스크에 나머지 필요한 버퍼를 스왑핑(swap)한다.

당연히 디스크를 버퍼로 사용하는 스왑핑이 이루어지면 소팅의 속도가 느려지게 된다.

2.6 pg_hba.conf

pg_hba.conf는 포스트그레스의 사용자들의 접근 권한 설정 파일이며 $PGDATA 디렉토리에 위치한다.

기타 자세한 내용은 포스트그레스 매뉴얼이나 DSN을 참고하기 바란다.

 

 

3. 기초편 1

3.1 문자열 상수 (String Constants)

 select text 'nogadax' AS CAST_str1;

    cast_str1 
   -----------
    nogadax
   (1 row)

 select 'ngd'::text AS CAST_str2;
 
   cast_str2 
   -----------
    ngd
   (1 row)

 select 'ngd\'s Home'::text AS CAST_str3;

    cast_str3  
   ------------
    ngd's Home
   (1 row)

 select 'ngd''s Home'::text AS CAST_str4;

    cast_str4  
   ------------
    ngd's Home
   (1 row)

3.2 Integer Constants

 select int8 '4000000000' as cast_i8_1;

    cast_i8_1  
   ------------
    4000000000
   (1 row)

 select 4000000000::int8 as cast_i8_2;

    cast_i8_2  
   ------------
    4000000000
   (1 row)

 select int8 '4000000000' + '4000000000'::int8 as cast_i8_3;

    cast_i8_3  
   ------------
    8000000000
   (1 row)

3.3 Floating Point Constants

 select float4 '1.55' as cast_f4_1;

    cast_f4_1 
   -----------
         1.55
   (1 row)

 select '1.55'::float4 as cast_f4_2;

    cast_f4_2 
   -----------
         1.55
   (1 row)

3.4 Data Types

 select bool 't' as bool_1;

    bool_1 
   --------
    t
   (1 row)

 select int2 '12', 13::int4, 14::int8, 100;

    ?column? | ?column? | ?column? | ?column? 
   ----------+----------+----------+----------
          12 |       13 |       14 |      100
   (1 row)

 select float4 '11.234511' as float4_1;

    float4_1 
   ----------
     11.2345
   (1 row)

 select float8 '11.234511' as float8_1;

    float8_1  
   -----------
    11.234511
   (1 row)

 select float8 '1211.2345112111' as float8_2;

       float8_2     
   -----------------
    1211.2345112111
   (1 row)

 select text 'ngd' as team_name , point '(1,2)' as location;

    team_name | location 
   -----------+----------
    ngd       | (1,2)
   (1 row)

select '2001-3-1'::date + 4 as date2;

    date2    
------------
 2001-03-5
(1 row)

select '2001-3-1'::date +'2 year'::interval as date3;

         date3          
------------------------
 2003-03-01 00:00:00+09
(1 row)

select '2001-3-1'::date +'3 month'::interval as date4;

         date4          
------------------------
 2001-06-01 00:00:00+09
(1 row)

select '2001-3-1'::date +'4 day'::interval as date5;

         date5          
------------------------
 2001-03-05 00:00:00+09
(1 row)

3.5 Function Constants

"getpgusername()"함수는 현재의 사용자 이름을 리턴한다.

 select getpgusername() AS cur_user_name ;

    cur_user_name 
   ---------------
    postgres
   (1 row)

"now" 는 현재시간을 갖는 특별한 변수이다.

 select date('now') as cur_date;

     cur_date  
   ------------
    2001-03-16
   (1 row)


 select time('now') as cur_time;

    cur_time 
   ----------
    19:14:17
   (1 row)


 select timestamp('now') as cur_transaction_date_time;

    cur_transaction_date_time 
   ---------------------------
    2001-03-16 19:14:17+09
   (1 row)

3.6 String Functions

 select char_length('nogadax') as char_length_1;

    char_length_1 
   ---------------
                7
   (1 row)


 select char_length('노가다') as char_length_2;

    char_length_2 
   ---------------
                3
   (1 row)


 select position('g' in 'nogada') as pos_1;

    pos_1 
   -------
        3
   (1 row)

3.7 SQL FUNCTIONs

NULLIF(input,value) 는 input==value 이면 NULL을 리턴하고 아니면 input 값을 리턴한다.

아래의 첫 예제는 NULL 을 리턴한다.

 select NULLIF('nn'::text,'nn'::text) as NULLIF_Test_1;

    nullif_test_1 
   ---------------
    
   (1 row)

 select NULLIF('nb'::text,'nn'::text) as NULLIF_Test_2;

    nullif_test_2 
   ---------------
    nb
   (1 row)

COALESCE(list) 의 list 는 "a,b,c,.."처럼 표현하고 리스트상의 인자중 NULL 값이 아닌 제일 첫 인자를 리턴한다.

 select COALESCE(1,2,3,4) AS COALESCE_Test_1;

    coalesce_test_1 
   -----------------
                  1
   (1 row)

 
 select COALESCE(5,6,7) AS COALESCE_Test_2;

    coalesce_test_2 
   -----------------
                  5
   (1 row)


 select COALESCE(8,9) AS COALESCE_Test_3;

    coalesce_test_3 
   -----------------
                  8
   (1 row)

"CASE WHEN expr THEN value1 ELSE value2 END" expr 이 참이면 value1을, 아니면 value2를 리턴한다.

 select 
  CASE 
    WHEN 'ngd'::text = 'ngd'::text
     THEN 'match'  ELSE 'no match'
  END ;


    case  
   -------
    match
   (1 row)



 select 
  CASE 
    WHEN 'ngd'::text = 'nogadax'::text
     THEN 'match'  ELSE 'no match'
  END ;


     case   
   ----------
    no match
   (1 row)

3.8 SQL FUNCTION을 이용한 함수 예제

 DROP FUNCTION SQL_FUNC_1(int4);
 DROP FUNCTION SQL_FUNC_2(int4);
 DROP TABLE NOGADA_TAB;

 create TABLE NOGADA_TAB (id_ngd int4 , name_ngd text);

 INSERT INTO NOGADA_TAB VALUES (1, 'ngd_1');
 INSERT INTO NOGADA_TAB VALUES (2, 'ngd_2');

 CREATE FUNCTION SQL_FUNC_1(int4) RETURNS text AS '
 SELECT
  CASE
     WHEN NOGADA_TAB.id_ngd = $1
       THEN ''있군요..''::text
       ELSE ''없군요..''::text
  END
 ' LANGUAGE 'sql';


  SELECT SQL_FUNC_1(1) ;


   sql_func_1 
  ------------
   있군요..
  (1 row)



 SELECT SQL_FUNC_1(3) ;


   sql_func_1 
  ------------
   없군요..
  (1 row)


 CREATE FUNCTION SQL_FUNC_2(int4) RETURNS text AS '
 SELECT
  CASE
     WHEN NOGADA_TAB.id_ngd = $1
       THEN NOGADA_TAB.name_ngd
       ELSE ''없군요..''::text
  END
 ' LANGUAGE 'sql';



  SELECT SQL_FUNC_2(1) as NOGADA_TAB_NAME;


   nogada_tab_name 
  -----------------
   ngd_1
  (1 row)

3.9 Full SQL SOURCE

다음은 위에서 설명한 전체 예제이다. copy하여 파일로 저장 후 PSQL 에서 테스트 할 수 있다. 참고로 "--" 시작하는 라인은 주석이다.

------------------------------------------------
-- By NoGaDa-X  (nogadax@kldp.org)
-- PostgreSQL's SQL Examples
-- (http://ngd.pe.kr)
-- /2001/03/15
------------------------------------------------

--String Constants

select text 'nogadax' AS CAST_str1;
select 'ngd'::text AS CAST_str2;
select 'ngd\'s Home'::text AS CAST_str3;
select 'ngd''s Home'::text AS CAST_str4;

--Integer Constants

select int8 '4000000000' as cast_i8_1;
select 4000000000::int8 as cast_i8_2;
select int8 '4000000000' + '4000000000'::int8 as cast_i8_3;

--Floating Point Constants

select float4 '1.55' as cast_f4_1;
select '1.55'::float4 as cast_f4_2;

--Data Types

select bool 't' as bool_1;
select int2 '12', 13::int4, 14::int8, 100;
select float4 '11.234511' as float4_1;
select float8 '11.234511' as float8_1;
select float8 '1211.2345112111' as float8_2;
select text 'ngd' as team_name , point '(1,2)' as location;

--Function Constants

select getpgusername() AS cur_user_name ;
select date('now') as cur_date;
select time('now') as cur_time;
select timestamp('now') as cur_transaction_date_time;

--String Functions

select char_length('nogadax') as char_length_1;
select char_length('노가다') as char_length_2;
select position('g' in 'nogada') as pos_1;

--SQL FUNCTIONs
--SQL FUNCTIONs

--NULLIF(input,value) 
--IF input==value THEN return NULL ELSE input

select NULLIF('nn'::text,'nn'::text) as NULLIF_Test_1;
select NULLIF('nb'::text,'nn'::text) as NULLIF_Test_2;

--COALESCE(list)
--list is (a,b,c,..)
--First-Non-NULL-value in list is returned

select COALESCE(1,2,3,4) AS COALESCE_Test_1;
select COALESCE(5,6,7) AS COALESCE_Test_2;
select COALESCE(8,9) AS COALESCE_Test_3;

--CASE WHEN expr THEN value1 ELSE value2 END

select 
  CASE 
    WHEN 'ngd'::text = 'ngd'::text
     THEN 'match'  ELSE 'no match'
  END ;
select 
  CASE 
    WHEN 'ngd'::text = 'nogadax'::text
     THEN 'match'  ELSE 'no match'
  END ;

--User-defined Function with SQL's Functions

DROP FUNCTION SQL_FUNC_1(int4);
DROP FUNCTION SQL_FUNC_2(int4);
DROP TABLE NOGADA_TAB;

create TABLE NOGADA_TAB (id_ngd int4 , name_ngd text);

INSERT INTO NOGADA_TAB VALUES (1, 'ngd_1');
INSERT INTO NOGADA_TAB VALUES (2, 'ngd_2');

CREATE FUNCTION SQL_FUNC_1(int4) RETURNS text AS '
SELECT
  CASE
     WHEN NOGADA_TAB.id_ngd = $1
       THEN ''있군요..''::text
       ELSE ''없군요..''::text
  END
' LANGUAGE 'sql';

SELECT SQL_FUNC_1(1) ;
SELECT SQL_FUNC_1(3) ;


CREATE FUNCTION SQL_FUNC_2(int4) RETURNS text AS '
SELECT
  CASE
     WHEN NOGADA_TAB.id_ngd = $1
       THEN NOGADA_TAB.name_ngd
       ELSE ''없군요..''::text
  END
' LANGUAGE 'sql';

SELECT SQL_FUNC_2(1) as NOGADA_TAB_NAME;

 

 

4. 기초편 2

다음의 test1, test2테이블은 아래의 예제들을 테스트하기 위한 테이블이다.

create table test1 (id_ngd int4, name_ngd text);

insert into test1 values(2, 'ngd1_2');
insert into test1 values(1, 'ngd1_1');
insert into test1 values(3, 'ngd1_3');
insert into test1 values(4, 'ngdx_4');
insert into test1 values(1, 'ngdx_4');

create table test2 (id_ngd int4, name_ngd text);

insert into test2 values(2, 'ngd2_2');
insert into test2 values(1, 'ngd2_1');
insert into test2 values(3, 'ngd2_3');
insert into test2 values(4, 'ngdx_4');
insert into test2 values(1, 'ngdx_4');

4.1 카티젼 곱 (cartesian product)

 select * from test1 , test2;

  id_ngd | name_ngd | id_ngd | name_ngd 
 --------+----------+--------+----------
       2 | ngd1_2   |      2 | ngd2_2
       1 | ngd1_1   |      2 | ngd2_2
       3 | ngd1_3   |      2 | ngd2_2
       4 | ngdx_4   |      2 | ngd2_2
       1 | ngdx_4   |      2 | ngd2_2
       2 | ngd1_2   |      1 | ngd2_1
       1 | ngd1_1   |      1 | ngd2_1
       3 | ngd1_3   |      1 | ngd2_1
       4 | ngdx_4   |      1 | ngd2_1
       1 | ngdx_4   |      1 | ngd2_1
       2 | ngd1_2   |      3 | ngd2_3
       1 | ngd1_1   |      3 | ngd2_3
       3 | ngd1_3   |      3 | ngd2_3
       4 | ngdx_4   |      3 | ngd2_3
       1 | ngdx_4   |      3 | ngd2_3
       2 | ngd1_2   |      4 | ngdx_4
       1 | ngd1_1   |      4 | ngdx_4
       3 | ngd1_3   |      4 | ngdx_4
       4 | ngdx_4   |      4 | ngdx_4
       1 | ngdx_4   |      4 | ngdx_4
       2 | ngd1_2   |      1 | ngdx_4
       1 | ngd1_1   |      1 | ngdx_4
       3 | ngd1_3   |      1 | ngdx_4
       4 | ngdx_4   |      1 | ngdx_4
       1 | ngdx_4   |      1 | ngdx_4
 (25 rows)

4.2 합집합 (UNION)

다음은 두개의 테이블을 합친다.

select id_ngd , name_ngd from test1
 union
select id_ngd , name_ngd from test2 ;

 id_ngd | name_ngd 
--------+----------
      1 | ngd1_1
      1 | ngd2_1
      1 | ngdx_4
      2 | ngd1_2
      2 | ngd2_2
      3 | ngd1_3
      3 | ngd2_3
      4 | ngdx_4
(8 rows)

4.3 차집합 (EXCEPT)

다음은 두개의 테이블에서 같은 항목은 뺀다.

select id_ngd , name_ngd from test1
 except
select id_ngd , name_ngd from test2 ;


 id_ngd | name_ngd 
--------+----------
      2 | ngd1_2
      1 | ngd1_1
      3 | ngd1_3
(3 rows)

4.4 교집합 (INTERSECT)

select id_ngd , name_ngd from test1
 intersect
select id_ngd , name_ngd from test2 ;

 id_ngd | name_ngd 
--------+----------
      4 | ngdx_4
      1 | ngdx_4
(2 rows)

4.5 Sub_query

select t1.name_ngd from test1 t1
WHERE t1.name_ngd IN
      (SELECT test2.name_ngd
       FROM test2 t2
       WHERE t2.id_ngd=4);

 name_ngd 
----------
 ngdx_4
 ngdx_4
(2 rows)


select t1.name_ngd from test1 t1
WHERE t1.name_ngd NOT IN
      (SELECT test2.name_ngd
       FROM test2 t2
       WHERE t2.id_ngd=4);

 name_ngd 
----------
 ngd1_2
 ngd1_1
 ngd1_3
(3 rows)

4.6 Aggregate Function

select AVG(t1.id_ngd) from test1 t1;
select max(t1.id_ngd) from test1 t1;
select min(t1.id_ngd) from test1 t1;
select count(t1.id_ngd) from test1 t1;
select sum(t1.id_ngd) from test1 t1;

 avg 
-----
   2
(1 row)

 max 
-----
   4
(1 row)

 min 
-----
   1
(1 row)

 count 
-------
     5
(1 row)

 sum 
-----
  11
(1 row)

4.7 group by, having

select id_ngd  from test1
where id_ngd >=1
group by id_ngd
having count(id_ngd) = 1; 

 
 id_ngd 
--------
      2
      3
      4
(3 rows)

4.8 JOIN and VIEW

VIEW는 가상 테이블입니다.

create table test3(id_01 int4, id_02 int4 ,in_03 int4);
create table test4(id_01 int4, id_name text);
insert into test3 values(1,2,3);
insert into test3 values(2,1,7);
insert into test3 values(3,5,7);
insert into test3 values(4,9,7);
insert into test4 values(1,'ngd_01');
insert into test4 values(2,'ngd_02');
insert into test4 values(5,'ngd_05');
insert into test4 values(6,'ngd_06');

select t3.id_01 ,  t4.id_name 
from test3 t3, test4 t4
where t3.id_01 = t4.id_01 ; 

 id_01 | id_name 
-------+---------
     1 | ngd_01
     2 | ngd_02
(2 rows)


create view join1
as select t3.id_01 ,  t4.id_name 
from test3 t3, test4 t4
where t3.id_01 = t4.id_01 ; 

select * from join1;

 id_01 | id_name 
-------+---------
     1 | ngd_01
     2 | ngd_02
(2 rows)

4.9 "LIKE" AND "order by"

다음의 예제에서 "%"는 0개 이상의 문자를 "_" 는 하나의 문자만을 의미한다.

select * from test1 where name_ngd like 'ng%' order by id_ngd;

 id_ngd | name_ngd
 -------+---------
      1 |  ngd1_1
      1 |  ngdx_4 
      2 |  ngd1_2
      3 |  ngd1_3
      4 |  ngdx_4
 (5 rows)


select * from test1 where name_ngd like 'ng_1%' order by id_ngd;

 id_ngd | name_ngd
 -------+---------
      1 |  ngd1_1
      2 |  ngd1_2
      3 |  ngd1_3
 (3 rows)

4.10 Like,  ,  * 예제

 create table xyz( x_txt text , y_txt text );

  insert into xyz values('abc' ,'def');
  insert into xyz values('cde' ,'efg');
  insert into xyz values('mmm' ,'yyy');
  insert into xyz values('ccc' ,'ddd');
  insert into xyz values('fff' ,'fff');
  insert into xyz values('가나다라' ,'마바사아자');
  insert into xyz values('구누두루' ,'무부수우주');

  select * from xyz where x_txt like '_bc';

   x_txt | y_txt 
  -------+-------
   abc   | def
  (1 row)

  select * from xyz where x_txt like '_Bc';

   x_txt | y_txt 
  -------+-------
  (0 rows)

  select * from xyz where y_txt like '%f%';

   x_txt | y_txt 
  -------+-------
   abc   | def
   cde   | efg
   fff   | fff
  (3 rows)

  select * from xyz where y_txt like '%F%';

   x_txt | y_txt 
  -------+-------
  (0 rows)

  --CASE SENSITIVE 대소문자 구분 ( ~ )
  select * from xyz where x_txt ~ '.*d.*';

   x_txt | y_txt 
  -------+-------
   cde   | efg
  (1 row)

  select * from xyz where x_txt ~ '.*D.*';

   x_txt | y_txt 
  -------+-------
  (0 rows)

  --CASE INSENSITIVE 대소문자 구분없음 ( ~* )
  select * from xyz where x_txt ~* '.*d.*';

   x_txt | y_txt 
  -------+-------
   cde   | efg
  (1 row)

  select * from xyz where x_txt ~* '.*D.*';

   x_txt | y_txt 
  -------+-------
   cde   | efg
  (1 row)

  select * from xyz where x_txt !~  '.*D.*';

    x_txt   |   y_txt    
  ----------+------------
   abc      | def
   cde      | efg
   mmm      | yyy
   ccc      | ddd
   fff      | fff
   가나다라 | 마바사아자
   구누두루 | 무부수우주
  (7 rows)

  select * from xyz where x_txt !~* '.*D.*';

    x_txt   |   y_txt    
  ----------+------------
   abc      | def
   mmm      | yyy
   ccc      | ddd
   fff      | fff
   가나다라 | 마바사아자
   구누두루 | 무부수우주
  (6 rows)

  select * from xyz where x_txt ~* '[a-c]';

   x_txt | y_txt 
  -------+-------
   abc   | def
   cde   | efg
   ccc   | ddd
  (3 rows)

  select * from xyz where x_txt !~ '[a-c]';

    x_txt   |   y_txt    
  ----------+------------
   mmm      | yyy
   fff      | fff
   가나다라 | 마바사아자
   구누두루 | 무부수우주
  (4 rows)

  select * from xyz where x_txt ~* '[가-누]';

    x_txt   |   y_txt    
  ----------+------------
   가나다라 | 마바사아자
   구누두루 | 무부수우주
  (2 rows)

  select * from xyz where y_txt !~ '[마-수]';

   x_txt | y_txt 
  -------+-------
   abc   | def
   cde   | efg
   mmm   | yyy
   ccc   | ddd
   fff   | fff
  (5 rows)
 

5. 중급편

 
 

5.1 primary,foreign key 예제 1

 
 
create sequence test1_seq ;

create table test1 ( 
  t_1_id   int4  default  nextval('test1_seq') ,
  t_1_name text  default  'N/A',
  primary key(t_1_id)
  );

create table test2 (
  t_2_id   int4 ,
  t_2_name text default 'N/A',
  t_2_item text default 'N/A', 
  CONSTRAINT const_test2
  FOREIGN KEY(t_2_id) REFERENCES test1
  ON DELETE CASCADE
  ON UPDATE CASCADE
  );

insert into test1(t_1_name) values('jone');
insert into test2 values(currval('test1_seq'),'jone','A-100');
insert into test1(t_1_name) values('sam');
insert into test2 values(currval('test1_seq'),'sam','B-500');

select * from test1;

    t_1_id | t_1_name 
   --------+----------
         1 | jone
         2 | sam
   (2 rows)


select * from test2;

   t_2_id | t_2_name | t_2_item 
  --------+----------+----------
        1 | jone     | A-100
        2 | sam      | B-500
  (2 rows)


delete from test1 where t_1_id=1;

select * from test1;

   t_1_id | t_1_name 
  --------+----------
        2 | sam
  (1 row)


select * from test2;

   t_2_id | t_2_name | t_2_item 
  --------+----------+----------
        2 | sam      | B-500
  (1 row)


update test1 set t_1_id=10 , t_1_name='abc'  where t_1_id=2;

select * from test1;

   t_1_id | t_1_name 
  --------+----------
       10 | abc
  (1 row)

select * from test2;

   t_2_id | t_2_name | t_2_item 
  --------+----------+----------
       10 | sam      | B-500
  (1 row)
 
다음의 예제는 위의 Example 1 예제와 거의 비슷합니다. 단지, Primary, Foreign Key에 두개의 column을 사용한 것만 빼고요.. 
 
----Example 2


create sequence test1_seq ;

create table test1 ( 
  t_1_id   int4  default  nextval('test1_seq') ,
  t_1_name text  default  'N/A',
  primary key(t_1_id, t_1_name)
  );

create table test2 (
  t_2_id   int4 ,
  t_2_name text default 'N/A',
  t_2_item text default 'N/A', 
  CONSTRAINT const_test2
  FOREIGN KEY(t_2_id, t_2_name) REFERENCES test1
  ON DELETE CASCADE
  ON UPDATE CASCADE
  );

insert into test1(t_1_name) values('jane');
insert into test2 values(currval('test1_seq'),'jane','A-100');
insert into test1(t_1_name) values('sam');
insert into test2 values(currval('test1_seq'),'sam','B-500');
insert into test1(t_1_name) values('tom');
insert into test2 values(currval('test1_seq'),'tom','C-150');

select * from test1;

    t_1_id | t_1_name 
   --------+----------
         1 | jane
         2 | sam
         3 | tom
   (3 rows)

select * from test2;

    t_2_id | t_2_name | t_2_item 
   --------+----------+----------
         1 | jane     | A-100
         2 | sam      | B-500
         3 | tom      | C-150
   (3 rows)

delete from test1 where t_1_id=1;

select * from test1;

    t_1_id | t_1_name 
   --------+----------
         2 | sam
         3 | tom
   (2 rows)

select * from test2;

    t_2_id | t_2_name | t_2_item 
   --------+----------+----------
         2 | sam      | B-500
         3 | tom      | C-150
   (2 rows)

update test1 set t_1_id=10 , t_1_name='abc'  where t_1_id=3;

select * from test1;

    t_1_id | t_1_name 
   --------+----------
         2 | sam
        10 | abc
   (2 rows)

select * from test2;

    t_2_id | t_2_name | t_2_item 
   --------+----------+----------
         2 | sam      | B-500
        10 | abc      | C-150
   (2 rows)
 

5.2 primary,foreign key 예제 2

 
 
--고객과 상품에는 판매라는 관계가 성립한다. 

   고객  TABLE                 상품 TABLE      
  +-----------+              +------------+ Primary Key     
  | 고객_번호 +--+ Primary   | 상품_번호  +---+   
  +-----------+  |           +------------+   |
  | 고객_성별 |  |           | 상품_이름  |   |
  +-----------+  |           +------------+   |
  | 고객_전화 |  |           | 상품_회사  |   |
  +-----------+  |           +------------+   |
  | 고객_주소 |  |           | 상품_가격  |   |
  +-----------+  |           +------------+   |
                 |                            |
                 |                            |
                 |                            |
                 |      판매 TABLE            |
                 |    +----------------+      |
                 |    | 판매_번호      |      |
                 |    +----------------+      |
                 +----+ 판매_고객_번호 |      |
              Foreign +----------------+      |
                      | 판매_상품_번호 +------+ 
                      +----------------+ Foreign Key    
                      | 판매_날짜      |   
                      +----------------+   
                      | 판매_개수      |   
                      +----------------+   
                      
다음은 위의 그림에 대한 예제입니다. 
 
create table 고객 (
 고객_번호   text , 
 고객_이름   text,
 고객_성별   bool,
 고객_전화   text, 
 고객_주소   text,
 primary key(고객_번호)
 );

create table 상품 (
 상품_번호  text, 
 상품_이름  text,
 상품_회사  text,
 상품_가격  int4,
 primary key(상품_번호)
);

create table 판매 (
 판매_번호         text, 
 판매_고객_번호    text,  
 판매_상품_번호    text,
 판매_날짜         date, 
 판매_개수         int4,

 constraint 고객_con 
 foreign key(판매_고객_번호) references 고객(고객_번호)  ,

 constraint 상품_con 
 foreign key(판매_상품_번호)  references 상품(상품_번호)
);


insert into 고객 values (
         '해운대구-001-남-30', 'nogadax', 't', 
         '051-729-7777', '부산시 해운대구 해운대 동백섬 1/1'
);

insert into 고객 values (
         '남구-002-남-27', 'ogler', 't', 
         '051-629-7887', '부산시 남구 용호동 2/1'
);

insert into 고객 values (
         '남구-003-남-32', 'winob', 't', 
         '051-629-2111', '부산시 남구 대연동 8/8'
);


insert into 상품 values 
     ('co-001-e-01' , 'TV'    , 'NGD co.' , 90000);
insert into 상품 values 
     ('co-008-e-02' , 'RADIO' , 'NGD co.' , 20000);
insert into 상품 values 
     ('co-011-e-01' , 'AUDIO' , 'NGD co.' , 70000);


select * from 고객;

    고객_번호      | 고객_이름 |..|             고객_주소             
-------------------+-----------+..+-----------------------------------
해운대구-001-남-30 | nogadax   |..| 부산시 해운대구 해운대 동백섬 1/1
남구-002-남-27     | ogler     |..| 부산시 남구 용호동 2/1
남구-003-남-32     | winob     |..| 부산시 남구 대연동 8/8
(3 rows)


select * from 상품;


  상품_번호  | 상품_이름 | 상품_회사 | 상품_가격 
-------------+-----------+-----------+-----------
 co-001-e-01 | TV        | NGD co.   |     90000
 co-008-e-02 | RADIO     | NGD co.   |     20000
 co-011-e-01 | AUDIO     | NGD co.   |     70000
(3 rows)


--integrity(무결성)에 문제가 없으므로.. 입력이 이루어진다. 

insert into 판매 values (
      '판매_001_S_Branch' , '남구-002-남-27', 
      'co-001-e-01' ,'2001-03-27',2
);


--integrity(무결성) error ..입력이 되지 않는다.  
--"남구-003-남-27"이란 값은  "고객" 테이블의 "고객_번호"에 없음.
--"co-001-e-02"   이란 값은  "상품" 테이블의 "상품_번호"에 없음

insert into 판매 values ('판매_001_S_Branch' , '남구-003-남-27', 
           'co-011-e-01' ,'2001-03-28',1
);

insert into 판매 values ('판매_001_S_Branch' , '남구-003-남-32', 
           'co-001-e-02' ,'2001-03-29',3
);

select * from 판매;

     판매_번호     | 판매_고객_번호 | 판매_상품_번호 | 판매_날짜  | 판매_개수 
-------------------+----------------+----------------+------------+-----------
 판매_001_S_Branch | 남구-002-남-27 | co-001-e-01    | 2001-03-27 |         2
(1 row)

 
 
다음은 위 예제의 Full SQL source이다. 
 
-------------------------------Cut here!!
drop index 고객_pkey;
drop index 상품_pkey;
drop table 고객; 
drop table 상품; 
drop table 판매; 

create table 고객 (
 고객_번호   text , 
 고객_이름   text,
 고객_성별   bool,
 고객_전화   text, 
 고객_주소   text,
 primary key(고객_번호)
 );

create table 상품 (
 상품_번호  text, 
 상품_이름  text,
 상품_회사  text,
 상품_가격  int4,
 primary key(상품_번호)
);

create table 판매 (
 판매_번호         text, 
 판매_고객_번호    text,  
 판매_상품_번호    text,
 판매_날짜         date, 
 판매_개수         int4,

 constraint 고객_con 
 foreign key(판매_고객_번호) references 고객(고객_번호)  ,
 constraint 상품_con 
 foreign key(판매_상품_번호)  references 상품(상품_번호)
);

insert into 고객 values (
         '해운대구-001-남-30', 'nogadax', 't', 
         '051-729-7777', '부산시 해운대구 해운대 동백섬 1/1'
);
insert into 고객 values (
         '남구-002-남-27', 'ogler', 't', 
         '051-629-7887', '부산시 남구 용호동 2/1'
);
insert into 고객 values (
         '남구-003-남-32', 'winob', 't', 
         '051-629-2111', '부산시 남구 대연동 8/8'
);


insert into 상품 values 
     ('co-001-e-01' , 'TV'    , 'NGD co.' , 90000);
insert into 상품 values 
     ('co-008-e-02' , 'RADIO' , 'NGD co.' , 20000);
insert into 상품 values 
     ('co-011-e-01' , 'AUDIO' , 'NGD co.' , 70000);

select * from 고객;
select * from 상품;


--integrity(무결성)에 문제가 없으므로.. 입력이 이루어진다. 

insert into 판매 values (
      '판매_001_S_Branch' , '남구-002-남-27', 
      'co-001-e-01' ,'2001-03-27',2
);


--integrity(무결성) error ..입력이 되지 않는다.  
--"남구-003-남-27"이란 값은  "고객" 테이블의 "고객_번호"에 없음.
--"co-001-e-02"   이란 값은  "상품" 테이블의 "상품_번호"에 없음

insert into 판매 values ('판매_001_S_Branch' , '남구-003-남-27', 
           'co-011-e-01' ,'2001-03-28',1
);
insert into 판매 values ('판매_001_S_Branch' , '남구-003-남-32', 
           'co-001-e-02' ,'2001-03-29',3
);

select * from 판매;
-----------------------------End ..
 

5.3 serial,sequence

 
다음은 serial 에제이다. 
--SERIAL (Auto-Sequence type)

drop sequence table_name1_colm_id_seq;
drop index table_name1_colm_id_key;
drop table table_name1;

DROP
DROP
DROP

create table table_name1(
 colm_id serial , 
 colm_name text
);

CREATE

insert into table_name1(colm_name) values('xxx');
insert into table_name1(colm_name) values('yyy');
insert into table_name1(colm_name) values('zzz');

INSERT 22729 1
INSERT 22730 1
INSERT 22731 1

select * from table_name1;

 colm_id | colm_name 
---------+-----------
       1 | xxx
       2 | yyy
       3 | zzz
(3 rows)
 
다음은 sequence 예제이다. 
 
drop sequence table_name2_colm_id_seq;
drop index table_name2_colm_id_key;
drop table table_name2;

DROP
DROP
DROP

create sequence table_name2_colm_id_seq;
create table table_name2(
 colm_id int4 default nextval('table_name2_colm_id_seq'), 
 colm_name text
);
create unique index table_name2_colm_id_key on table_name2(colm_id);

CREATE
CREATE
CREATE

insert into table_name2(colm_name) values('aaa');
insert into table_name2(colm_name) values('bbb');
insert into table_name2(colm_name) values('ccc');

INSERT 22763 1
INSERT 22764 1
INSERT 22765 1

select * from table_name2;

 colm_id | colm_name 
---------+-----------
       1 | aaa
       2 | bbb
       3 | ccc
(3 rows)
 

5.4 Function

 
CREATE TABLE FUNCTION_NAME([PARAM1,PARAM2,..]) RETURNS [SETOF] DATA_TYPE
AS ' 
   USER_DEFINITION 
' LANGUAGE 'lang';
위의 []는 생략 가능함을 의미한다. lang에는 sql,plpgsql,c 등이 올수 있다. 
 
다음은 앞부분(기초편1)에서 언급된 function 예이다. 실행 결과는 앞부분을 참조하라. 
 
 CREATE FUNCTION SQL_FUNC_1(int4) RETURNS text AS '
 SELECT
  CASE
     WHEN NOGADA_TAB.id_ngd = $1
       THEN ''있군요..''::text
       ELSE ''없군요..''::text
  END
 ' LANGUAGE 'sql';

  SELECT SQL_FUNC_1(1) ;
 
다음은 포스트그레스의 function으로 간단한 예와 그 결과이다. 
 
    create function func1() returns text
    as ' select \'nogadax\'::text \; ' 
    language 'sql';


    select func1() as name;

      name 
   -------
   nogadax
   (1 row)
 
 
returns 에 예약어 setof 를 사용하면 한번에 여러 데이타를 받을 수 있다. 리턴형에는 일반 자료형뿐만아니라 테이블이나 뷰도 포함된다. 
 
    create table tablex (id_t int4, name text);
       
    insert into tablex values ( 1, 'abc'); 
    insert into tablex values ( 2, 'bcd');        
    insert into tablex values ( 3, 'cde');        
    insert into tablex values ( 4, 'def');        

    create function func2(int4) returns setof tablex
    as ' select * from tablex where id_t > $1 '
    language 'sql';

    select id_t(func2(1)) as id ;
        
      id
     ---
       2
       3
       4
   (3 rows)

    select id_t(func2(2)) as id , name(func2(2)) as name;

    id  |   name
   -----+-------- 
     3  |    cde
     4  |    def
  (2 rows)
 
 

5.5 PL/pgSQL

 
PL/pgSQL은 PGLIB의 plpgsql.so를 필요로 하며 이 파일을 핸들러 혹은 처리기라 한다. PL/pgSQL을 사용하기 위해서는 핸들러를 데이타베이스에 등록하여야 한다. 참고로 트리거에서 PL/pgSQL 이 사용될때는 트리거 프로시져라 한다. 다음은 등록 예이다. 
 
 $ su - postgres
 $ createlang plpgsql template1
 $
 
다음은 PL/pgSQL의 예이다. 
 
create function test(int4)returns int4
as ' 
  begin 
    return $1;
   end;
' language 'plpgsql';

 select test(2) ;

  test
  ----
    2
  (1 rows)
 

5.6 트리거 프로시져

트리거 프로시져란 트리거에서 사용되는 FUNCTION 을 의미하며 PL/pgSQL이 트리거에서 사용될 경우도 마찬가지로 트리거 프로시져라 한다. 
 
PL/pgSQL 이 트리거 프로시져로 시용될 때 특별히 사용되는 변수들이 있다. 다음은 트리거 프로시져 변수들의 예이다. 
 
  • NEW : ROW LEVEL 트리거에서 INSERT/UPDATE 의 결과로 새로 생서외었거나 갱신된 ROW (RECORD타입이다.)
  • OLD : NEW 와 비슷하나 DELETE/UPDATE 의 동작 전의 해당 ROW
  • TG_NAME : NAME형이며 트리거명이 저장된다.
  • TG_WHEN : AFTER나BEFORE가 저장된다.
  • TG_OP : INSERT, DELETE 등의 이벤트가 저징된다.
기타 자세한 것은 관련 문서를 찾아보기 바란다. 
 

5.7 트리거

 
 
트리거는 하나의 ROW에 대해 동작한다(FOR EACH ROW). 즉, 동시에 여러 ROW에 대해 처리가 이루어지지 않는다. 이는 RULE과의 차이점이다. 다음은 트리거 예제이다. 
 
CREATE TABLE test_table1 (test_id int, test_name text);
CREATE TABLE test_table2 (test_id int, test_name text);

insert into test_table1 values(1,'jini1');
insert into test_table2 values(1,'jini1');
insert into test_table1 values(2,'jini2');
insert into test_table2 values(2,'jini2');

insert into test_table1 values(10,'jini10');
insert into test_table1 values(15,'jini15');
insert into test_table1 values(19,'jini19');
insert into test_table1 values(20,'jini20');

select * from test_table1;

 test_id | test_name 
---------+-----------
       1 | jini1
       2 | jini2
      10 | jini10
      15 | jini15
      19 | jini19
      20 | jini20
(6 rows)

select * from test_table2;


   test_id | test_name 
  ---------+-----------
         1 | jini1
         2 | jini2
  (2 rows)

--RAISE 는 예외 처리자이며 NOTICE, EXCEPTION 등이 올 수 있다. 
--RAISE 뒤의 EXCEPTION 은 예외 발생시 해당 트랜잭션을 중지한다.

CREATE FUNCTION test_func1() RETURNS OPAQUE AS '
 BEGIN
   IF NEW.test_id < 20  THEN 
    RAISE NOTICE ''너무 작아요. % %'', TG_RELNAME ,TG_OP;
   END IF;
   RETURN OLD;
 END; 
' language 'plpgsql';

CREATE TRIGGER test_trg1 AFTER INSERT ON test_table1
FOR EACH ROW EXECUTE PROCEDURE test_func1();


insert into test_table1 values(10,'jini10');

NOTICE: 너무 작아요. test_table1 INSERT
psql:test_trg:76 NOTICE:  너무 작아요. test_table2 INSERT
INSERT 21228 1


insert into test_table1 values(15,'jini15');

NOTICE: 너무 작아요. test_table1 INSERT
psql:test_trg:77 NOTICE:  너무 작아요. test_table2 INSERT
INSERT 21229 1


select * from test_table1;

   test_id | test_name 
  ---------+-----------
         1 | jini1
         2 | jini2
        10 | jini10
        15 | jini15
        19 | jini19
        20 | jini20
        10 | jini10
        15 | jini15
  (8 rows)
 
 

5.8 Rule examples

 
 
instead 있는 액션은 user command 실행안함. 여기서의 user command 는 rule1 을 기동하는 test1 에 대한 insert .. SQL 문이다. 즉, rule1 의 test1테이블에 대한 insert 명령은 실행되지 않고 do instead 뒤의 update문만 실행됨. instead 가 없다면 do 뒤의 action을 취하고 user command 가 실행됨 
 
create table test1(tid int4,tname text);
create table test2(tid int4,tname text);

insert into test1 values(1,'test1');
insert into test2 values(2,'test2');

create rule rule1 as on insert to test1
do instead update test1 set tname='t1';

create rule rule2 as on insert to test2
do update test2 set tname='t2';

insert into test1 values(3,'test1');
insert into test2 values(4,'test2');

select * from test1;


 tid | tname 
-----+-------
   1 | t1
(1 row)


select * from test2;

 tid | tname 
-----+-------
   2 | t2
   4 | test2
(2 rows)
 
create view 가 아닌 create rule를 사용하여 view 를 생성할 경우 해당 테이블에 대한 새로운 빈 테이블을 생성하고 그 테이블을 view로 사용한다. 
 
아래의 예에서 "_RETtest3"은 특별한 rule 이름으로서 rule 로 view 를 생성할 경우의 예약어 구실을 한다. 즉, test3 에 대한 view 를 만들려는 rule의 경우 해당 view명은 "_RETtest3" 으로 정해야 한다. 
 
--view rule for test3

create table test3(tid int4,tname text);
create rule "_RETtest3" as on select to test3 
do instead select * from test1;

select * from test3;

 tid | tname 
-----+-------
   1 | t1
(1 row)
 
rule이 제대로 등록되었는지 확인코자 시스템 카탈로그인 pg_rewrite를 검색한다. 
 
select rulename from pg_rewrite;

    rulename    
----------------
 _RETpg_user
 _RETpg_rules
 _RETpg_views
 _RETpg_tables
 _RETpg_indexes
 rule1
 rule2
 rule3
 _RETtest3
(9 rows)
 
 

5.9 시스템 카탈로그 활용 예

 
다음은 시스템 카탈로그의 활용 예이다. 
--Select database_name

 SELECT pg_database.datname , pg_user.usename      
  FROM   pg_database, pg_user      
  WHERE  pg_database.datdba = pg_user.usesysid ;


  datname  | usename  
-----------+----------
 postgres  | postgres
 betty     | postgres
 nogada    | postgres
 jini      | postgres
 winob     | postgres
 template1 | postgres
 registdb  | webdb
 test2     | speedall
 test1     | lockmind
(9 rows)


--select system_relation

SELECT c.relname as Name, 'table'::text as Type, u.usename as Owner
  FROM pg_class c, pg_user u
  WHERE c.relowner = u.usesysid AND c.relkind = 'r'
    AND not exists (select 1 from pg_views where viewname = c.relname)
    AND c.relname ~ '^pg_';

      name      | type  |  owner   
----------------+-------+----------
 pg_type        | table | postgres
 pg_attribute   | table | postgres
 pg_proc        | table | postgres
 pg_class       | table | postgres
 pg_group       | table | postgres
 pg_database    | table | postgres
 pg_attrdef     | table | postgres
 pg_relcheck    | table | postgres
 pg_trigger     | table | postgres
 pg_inherits    | table | postgres
 pg_index       | table | postgres
 pg_statistic   | table | postgres
 pg_operator    | table | postgres
 pg_opclass     | table | postgres
 pg_am          | table | postgres
 pg_amop        | table | postgres
 pg_amproc      | table | postgres
 pg_language    | table | postgres
 pg_aggregate   | table | postgres
 pg_ipl         | table | postgres
 pg_inheritproc | table | postgres
 pg_rewrite     | table | postgres
 pg_listener    | table | postgres
 pg_description | table | postgres
 pg_shadow      | table | postgres
(25 rows)


--select normal_relation

SELECT c.relname as Name, 'table'::text as Type, u.usename as Owner
   FROM pg_class c, pg_user u
   WHERE c.relowner = u.usesysid AND c.relkind = 'r'
     AND not exists (select 1 from pg_views where viewname = c.relname)
     AND c.relname !~ '^pg_';

    name    | type  | owner 
------------+-------+-------
 regist_tab | table | webdb
(1 row)


-- * Get general table info 

SELECT relhasindex, relkind, relchecks, reltriggers, relhasrules
  FROM pg_class WHERE relname='regist_tab';

 relhasindex | relkind | relchecks | reltriggers | relhasrules 
-------------+---------+-----------+-------------+-------------
 f           | r       |         0 |           0 | f
(1 row)


-- * Get column info 

SELECT a.attname, t.typname,a.atttypmod-4 as Type_Length,t.typalign, 
          t.typlen ,a.attstorage,a.attnotnull, a.atthasdef, a.attnum
         
   FROM pg_class c, pg_attribute a, pg_type t
   WHERE c.relname = 'regist_tab'
   AND a.attnum > 0 AND a.attrelid = c.oid AND a.atttypid = t.oid
   ORDER BY a.attnum;

 attname | typname | type_length |..| atthasdef | attnum 
---------+---------+-------------+..+-----------+--------
 a       | varchar |           2 |..| f         |      1  
 b       | varchar |           4 |..| f         |      2  
 c       | varchar |           6 |..| f         |      3
(3 rows)


--기타 시스템 카탈로그 SQL 문 

select tablename from pg_tables;
select relname,relhaspkey from pg_class;
select datname from pg_database;?
 

5.10 pg_shadow,pg_user

 
다음은 포스트그레스를 설치 후 포스트그레스의 슈퍼유저 postgres 유저에게 패스워드를 할당하는 예이며 패스워드를 할당 후 유저 정보를 살피는 예이다. "alter user .."는 기존의 사용자 정보를 수정한다. 각각의 명령은 슈퍼유저 "postgres"로 실행하였다. 
 
template1=# alter user postgres with password 'abxy912q';
ALTER USER

template1=# select * from pg_user;

 usename  | usesysid | usecreatedb |..| usecatupd |  passwd  | valuntil 
----------+----------+-------------+..+-----------+----------+----------
 postgres |      501 | t           |..| t         | ******** | 
(1 row)

template1=# select * from pg_shadow;

 usename  | usesysid | usecreatedb |..| usecatupd |  passwd  | valuntil 
----------+----------+-------------+..+-----------+----------+----------
 postgres |      501 | t           |..| t         | abxy912q | 
(1 row)

template1=#

관련글 더보기