이 문서의 테스트환경은 다음과 같다.
다음은 인터넷을 통해 "postgresql"과 관련된 자료를 참조할 수 있는 사이트들이다.
또한, 미흡한 필자의 홈페이지 http://ngd.pe.kr에서 관련 문서들을 참조할 수 있다.
현재 이문서에는 필자가 모르는 오타가 있을 것이고, 논리에 맞지않는 부분도 있을 것입니다. 이러한 부분에 대해 메일로 지적을 해 준다면 다음 수정판에 꼭 반영할 것입니다.
이글을 읽고서 기타 추가사항이 있다면 주저없이 메일로 보내주시면 고맙겠습니다.
끝으로 이글에 대한 질문들, 즉 SQL이나 포스트그레스 자체에 대한 질문들은 받지 않습니다.
포스트그레스는 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
initdb 는 포스트그레스의 데이타베이스들을 관리하기 위한 정보 및 데이타베이스를 저장할 디렉토리를 만들며, 포스트그레스가 기동되기전에 실행되어져야 한다. 기타 포스트그레스와 관련된 여러가지 초기화 작업을 한다.
initdb 는 환경변수 PGDATA 값을 참조하여 /pgsql_base_dir/data 디렉토리를 만들며 /pgsql_base_dir/data/base 디렉토리에 각 데이타베이스들이 저장된다.
참고로 포스트그레스의 initdb 실행 후 template1이라는 데이타베이스가 생성된다.
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
$
"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
$
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의 결과에 대한 설명이다.
$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)한다.
당연히 디스크를 버퍼로 사용하는 스왑핑이 이루어지면 소팅의 속도가 느려지게 된다.
pg_hba.conf는 포스트그레스의 사용자들의 접근 권한 설정 파일이며 $PGDATA 디렉토리에 위치한다.
기타 자세한 내용은 포스트그레스 매뉴얼이나 DSN을 참고하기 바란다.
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)
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)
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)
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)
"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)
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)
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)
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)
다음은 위에서 설명한 전체 예제이다. 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;
다음의 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');
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)
다음은 두개의 테이블을 합친다.
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)
다음은 두개의 테이블에서 같은 항목은 뺀다.
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)
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)
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)
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)
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)
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)
다음의 예제에서 "%"는 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)
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)
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)
--고객과 상품에는 판매라는 관계가 성립한다. 고객 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 ..
다음은 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)
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)
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)
트리거 프로시져란 트리거에서 사용되는 FUNCTION 을 의미하며 PL/pgSQL이 트리거에서 사용될 경우도 마찬가지로 트리거 프로시져라 한다.
PL/pgSQL 이 트리거 프로시져로 시용될 때 특별히 사용되는 변수들이 있다. 다음은 트리거 프로시져 변수들의 예이다.
기타 자세한 것은 관련 문서를 찾아보기 바란다.
트리거는 하나의 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)
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)
다음은 시스템 카탈로그의 활용 예이다.
--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;?
다음은 포스트그레스를 설치 후 포스트그레스의 슈퍼유저 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=#