SQL문 기본

Oracle 2007. 1. 21. 17:47
SQL문 기본
데이타베이스에서 데이타를 질의한다.(Select)데이타를 입력(Insert), 수정(Update), 삭제(Delete)한다.데이타 구조를 생성(Create), 수정(Alter), 삭제(Drop)한다데이타 액세스를 조절한다(Grant)
    1. SQL문의 종류
SQL문의 종류에는
    DDL(Data Definition Language테이블/데이타의 구조를 조작하는 명령)DML(Data Manupulation Language : 데이타를 조작하는 명령)Session Control(세션을 제어하는 명령)System Control(시스템을 제어하는 명령)Transaction Control(트랜잭션을 제어하는 명령)
등이 있다. (아래 표 참고)
Data DefinitionData ManupulationSystem Control
ALTERANALYZEAUDITCOMMENTCREATEDROPGRANTNOAUDITRENAMEREVOKETRUNCATE
DELETEEXPLAIN PLANINSERTLOCK TABLESELECTUPDATE
ALTER SYSTEM
Transaction Control
COMMITROLLBACKSAVEPOINTSET TRANSACTION
Session Control
ALTER SESSIONSET ROLE
Table 2-1. SQL문 종류
ALTER : 데이타베이스를 변경할 때 사용ANALYZE : 데이타베이스의 통계자료를 생성시에 사용AUDIT: SQL문을 auditing하기 위해 지정하는 명령.COMMENT : table, view, snapshot 또는 column에 관한 comment를 데이터 딕셔너리에 입력할 때 사용CREATE : table, index, view, snapshot, cluster, database, database link 등과 같은 database object를 생성시에 사용DROP : database object삭제하는 명령.RENAME : table, view, sequence, private synonym의 이름을 변경하는 명령.NOAUDIT :AUDIT에 의해 선택된 SQL문의 audit를 정지시키는 명령.REVOKE : object의 권한을 취소하는 명령.TRUNCATE : 테이블이나 cluster의 모든 row를 삭제하는 명령.DELETE : 테이블이나 view의 base테이블의 row를 삭제하는 명령EXPLAIN PLAN : SQL문의 실행계획을 결정하는 명령.INSERT : 테이블, VIEW의 BASE테이블에 ROW를 추가하는 명령.LOCK TABLE : 1개 또는 여러 개의 테이블을 LOCK하는 명령.SELECT : 테이블, VIEW, SNAPSHOT에서 ROW를 구해오는 명령.UPDATE : TABLE, VIEW의 BASE TABLE의 존재하는 ROW의 값을 변경하는 명령.ALTER SESSION : 유저가 권한이 있는 세션을 제어하는 명령.SET ROLE : 현재의 세션의 ROLE을 ENABLE/DISABEL시키는 명령.ALTER SYSTEM : 오라클 인스턴스를 변경하는 명령.COMMIT: 현재의 트랜잭션을 종료하고, 트랜잭션 도중 변경되어진 데이타를 확정하는 명령.ROLLBACK : 현재의 트랜잭션을 취소하고 변경되어진 데이타를 변경전의 데이타로 복구.SAVEPOINT : 트랜잭션에서 나중에 ROLLBACK할 위치를 지정하는 명령.SET TRANSACTION : 현재의 트랜잭션에서 트랜잭션을 READ-ONLY로 하거나 READ-WRITE로 설정, 트랜잭션에서 사용될 ROLLBACK SEGMENT를 지정한다. TIP> SQLPLUS에서 HELP를 보는 방법
    SQL>HELP [명령어] 하면 된다.
    2. 기본적인 SQL문
SELECT 한개 혹은 여려개의 테이블에서 ROW를 리턴한다.INSERT 테이블에 새로운 ROW를 추가한다.UPDATE 테이블의 ROW를 수정한다.DELETE 테이블에서 ROW를 삭제한다.다음 SQL문들은 Embeddec SQL문에서 CURSOR를 정의하고 조작하는데 사용된다.
    DECLARE CURSOR를 선언한다.ALLOCATE CURSOR변수에 메모리를 할당한다.OPEN QUERY를 사용가능하게 수행하여 active set을 생성한다.FETCH active set에서 각 ROW를 가져온다.CLOSE CURSOR를 종료한다.
SELECT 문SELECT문에서 사용되는 예약어들은
    INTO, FROM, WHERE , CONNECT BY, START WITH,GROUP BY,HAVING,ORDER BY,FOR UPDATE OF 등이 있다.
    EXEC SQL SELECT ename, job, sal + 2000 INTO :emp_name, :job_title, :salary FROM emp WHERE empno = :emp_number;
INSERT문
    EXEC SQL INSERT INTO emp (empno, ename, sal, deptno) VALUES ( :emp_number, :emp_name, :salary, :dept_number);
subquery의 사용
    subquery는 INSERT문장이나 CREATE TABLE문장 뒤에서, UPDATE문의 컬럼을 명시하는 것으로 사용가능하다.EXEC SQL INSERT INTO emp2 (empno, ename, sal, deptno) SELECT empno, ename, sal, deptno from emp WHERE job = :job_title;
UPDATE문의 사용
    EXEC SQL UPDATE emp SET sal = :salary, comm = :commission WHERE empno = :emp_number;UPDATE문에서도 subquery를 사용할 수 가 있는데 SET절에서 컬럼 뒤에 사용한다.EXEC SQL UPDATE emp SET sal = (SELECT AVG(sal) *1.1 FROM emp WHERE deptno = 20) WHERE empno = :emp_number;
DELETE문
    EXEC SQL DELETE emp WHERE empno = :emp_number;INSERT를 제외한 SELECT, UPDATE, DELETE에서는 WHERE절을 사용가능한데, 이 WHERE절은 테이블의 특정한 ROW를 찾는 검색조건이다.
    3. CURSOR의 사용
여러 개의 ROW를 query할 경우 사용한다.CURSOR의 사용은 DECALRE, OPEN, FETCH, CLOSE의 4개의 명령으로 사용 가능하다.처음에 DECALRE문으로 CURSOR를 선언한다. 커서의 선언은 명시적으로 SQL QUERY문에 커서의 이름을 대응시키는 것이다.
    EXEC SQL DECLARE emp_cursor CURSOR FOR SELECT ename, empno, sal FROM emp WHERE deptno = :dept_number;
CURSOR명에는 하이픈(“-“)이 들어가는 안되고, 길이는 상관이 없는데 처음 31자는 의미가 있어야 한다. ANSI모드에서는 18자로 제한되어 있다.CURSOR를 정의한 SELECT문장에는 INTO절은 사용하지 않는다.실제적으로 CURSOR를 실행하는 부분은 OPEN이다.
    EXEC SQL OPEN emp_cursor;
커서를 DECLARE하기 전에 먼저 OPEN을 하면 OPEN에서 에러가 발생된다.커서는 OPEN시점에서 실제적으로 QUERY를 수행하여 데이타를 추출한다.OPEN이 되었다면 데이타는 FETCH문으로 어플리케이션 프로그램으로 가져온다.
    EXEC SQL FETCH emp_cursor INTO :emp_name, :emp_number, :salary;
이 FETCH문장은 더 이상 가져올 데이타가 없을 때까지 실행되어야 하니까, LOOP한에 위치하게 된다..
    while(1){ EXEC SQL FETCH emp_cursor INTO :emp_name, :emp_number, :salary; if(sqlca.sqlcode == 1403) { printf("No Data Found !\n"); break; } else if(sqlca.sqlcode != 0 ) { printf(" Oracle Error Detected!!: %d\n%s\n", sqlca.sqlcode,sqlca.sqlerrmc); break; } printf("%s:%s:%d\n",emp_name, emp_number, salary);}
더 이상 데이타가 존재하지 않으면 CLOSE를 사용하여 커서를 FREE시켜야 한다.
    EXEC SQL CLOSE emp_cursor;
이렇게 함으로써 커서가 점유하고 있던 resource를 데이타베이스에게 되돌려 준다.

이 커서가 다시 사용된다면 CLOSE하지 말고 DECLARE에서 사용된 호스트 변수에 원하는 값을 다시 부여하고 OPEN부터 다시 수행시켜 PARSING의 부하를 줄일 수 있다. 커서는 재사용 될 수 있다.
    EXEC SQL DECLARE emp_cursor CURSOR FOR SELECT ename, job FROM emp WHERE empname = :emp_number;while(1) { scanf(emp_number,"%s"); if(strcmp(deptno,"0")==0) break; EXEC SQL OPEN emp_cursor while(1) { EXEC SQL FETCH emp-cursor INTO :emp_name, :job_title; if(sqlca.sqlcode == 1403) break; if(sqlca.sqlcode != 0) { printf("ORACLE Error !!1 %d",sqlca.sqlcode); break; } printf("%s%s\n",emp_name, job_title); }}EXEC SQL CLOSE emp_cursor;
    4. 내부커서, 외부커서
오라클은 SQL문을 수행하기 위하여 PGA(Program Global Area)작업영역을 사용한다. PGA는 SQL문장 수행에 필요한 정보들을 저장하는 CURSOR에 의해 각 SQL문을 제어 하도록 구성되어 있다. 커서에는 내부 커서와 외부커서가 있다. 모든 DDL과 DML에 대해 내부적으로 커서를 생성시킨다. 그러나 다중처리 단위를 여러 번 수행시키고자 한다면 외부커서를 선언하여 사용해야만 한다. 내부커서
    오라클은 SQL문장에 대해서 무조건 내부 커서를 생성하며 이 커서는 보관 커서를 지정하지 않는 이상 DECLARE/OPEN/FETCH/CLOSE 작업을 매번 자동적으로 수행된다. 또한 한개의 ROW를 추출하는 문장이나 다중처리로 추출하는 경우도 마찬가지로 작동된다.
외부커서
    앞에서 살펴본 프로그래머가 커서를 선언하여 OPEN/FETCH/CLOSE를 하는 커서를 말한다.
HOLD_CURSOR의 사용루프내에서 사용되어질 프로그램에 대해서는 파싱은 한번만 하면 된다. 그렇게 하기 위해서는 프로그래머가 임의적으로 HOLD_CURSOR, RELEASE_CURSOR옵션을 지정해 주어야만 내부커서를 보관할 수 있다.만약 이렇게 보관시켜야 할 커서의 숫자가 10개가 넘어간다면 MAXOPENCURSOR 옵션을 늘려 주어야 한다. 이 옵션은 기본적으로 10개로 잡혀있다.
출처 : http://blog.naver.com/nsjung74/110007853741

'Oracle' 카테고리의 다른 글

PROC 에서 외부 환경변수를 받아 들이는 방법  (0) 2007.01.21
Dynamic SQL의 사용  (0) 2007.01.21
Pro*C에서 변수의 사용  (0) 2007.01.21
proc 파헤치기  (0) 2007.01.21
LINUX + ORACLE 10g 10.1 Install  (0) 2006.06.11
, .
Pro*C에서 변수의 사용
    1. 데이터의 Type
데이타 타입
C변수 타입설명
charsingle charactor
char[n]
n-charactor array(string)
Int
integer
Short
small integer
Long
large integer
Float
floating-point number(usually single precision)
Double
floating-point number(always double precision)
VARCHAR[n]
variable-length string
<table 3-1>호스트 변수를 위한 C데이타 타입

    C와 Oracle 데이타 타입 호환성
Internal Type(Oracle)C Type설명
VARCHAR2(Y)(Y:1~2000)
char
single charactor
CHAR(X)(X:1~255)
char[n]VARCHAR[n]intshortfloat
n-byte charactor arrayn-byte variable-length charactor arrayintegersmall integer
NUMBERNUMBER(P,S)
intshortlongfloatdoublecharchar[n]VARCHAR[n]
integersmall integerlarge integerfloating-point numberdouble-precision floating-point numbersingle charactern-byte character arrayn-byte variable-length character array
DATE
char[n]VARCHAR[n]
n-byte character arrayn-byte variable-length character array
LONG
char[n]VARCHAR[n]
n-byte character arrayn-byte variable-length character array
RAW(X)
unsigned char[n]VARCHAR[n]
n-byte character arrayn-byte variable-length character array
LONG LAW
unsigned char[n]VARCHAR[n]
n-byte character arrayn-byte variable-length character array
ROWID
unsigned char[n]VARCHAR[n]
n-byte character arrayn-byte variable-length character array
MLSLABEL
unsigned char[n]VARCHAR[n]
n-byte character arrayn-byte variable-length character array
Notes:
    X : 1~255 사이의 값 default 1Y : 1~2000사이의 값P : 2~38 , S : -84~127사이의 값
<table 3-2> C와 Oracle 데이타 타입 호환성
    2. Internal Data Type - 오라클 데이타 타입
문자 데이타 타입- char와 varchar2 datatype은 alphanumeric data로 저장.- database character set은 database를 생성할때 만들어지며 변경할 수 없다.
    ⓛ char datatype
      - fixed-length character strings.- table을 생성할때 칼럼길이가 정의되며 1~255 bytes.(default 1)- table의 row를 insert나 update할때 char 칼럼은 고정된 length를 가짐.- 정해진 값보다 짧은 값이 입력되면 정해진 length만큼 이후는 blank가 채워짐.- trailing blank를 가진 정해진 값보다 긴 값이 입력되면 고정된 길이 내에서 trailing blank가 잘림.정해진 길이보다 긴 값이 입력되면 오라클은 에러를 return.
    ② Varchar2 datatype
      - variable-length character strings.- maximum 칼럼 length는 1~2000 bytes.- 입력된 길이 만큼만 저장됨.
    ③ Varchar datatype
      - varchar2 datatype 과 현재는 동일함.- 향후 오라클에서는 다른 용도로 사용계획. (varchar2를 사용하는 것이 향후에 유리)
      3. 어떻게 데이타 타입을 정할 것인가?
    Semantics 비교
      ANSI처럼 trailing blank 가 중요한 역할을 하지 않을때는 char사용.trailing blank 가 중요한 역할을 담당할때는 varchar2 사용.효과적인 데이터 저장을 위해서는 varchar2 가 유리.char datatype은 blank-pad를 하고 trailing blank를 fix 된 칼럼 길이 만큼 blank를 채워 저장.varchar2는 blank를 저장하지 않음.
        blank-pad : 'a'='a ', non-pad 'a '>'a'Future Compatibility
      char와 varchar2 datatype은 지원이 되지만 varchar datatype는 향후 어떤 용도로 사용될지 모르기 때문에 사용하지 않는것이 좋다.
    Number 데이타 타입
      fixed floating-point number로 저장.number (precision, scale)
        precision-scale= 왼쪽정수의 수,scale은 오른쪽 소수이하의 수. (단,scale이 +일 경우) 38digits 까지 저장가능.
      scale은 -84~127사이① Internal numeric format
        variable-length format.38digits 까지 저장가능. 지수가 1bytes 일때 가수는 20bytes까지 가능. (38digit/2)+1=20bytes4.12×10E2 일때 지수 1 bytes 차지 4,1,2 2bytes 차지. (3digits /2)=1.5 1+1=2bytes지수의 범위는 -130~125 사이
    Date 데이타타입
      point-in-time value 으로 저장.Jan 1,4712 BC ~ Dec 31,4712 AD (AD가 default)기본형태는 DD-MON-YY기본 형태에서 벗어나는 날짜를 사용할때는 TO_DATE function을 사용.TO_DATE ('November 13,1992', 'MONTH DD,YYYY')ⓛ Julian date01-01-4712 BC부터 원하는 날까지의 날수 계산시 사용.format mask “J" 사용.TO_DATE 와 TO_CHAR fuction을 사용하여 date datatype과 상호 convert가능.select to_char (hiredate, 'J') from emp;(date type인 hiredate를 julian date로 convert)insert into emp (hiredate) values (to_date(2448921, 'J'));(julian date인 2448921을 date datatype으로 변환하여 hiredate 칼럼에 insert.)
    Long 데이타타입
      variable-length character data2 gigabytes 까지의 data 저장.long data는 text data 이고 다른 시스템으로 옮길때 convert되어짐.주로 comment 등에 사용되어지는 datatype.사용자가 특별히 지정하지 않으면 80 bytes 만 출력.하나의 테이블에는 오직 하나의 long datatype 만 존재.not (null)을 제외한 다른 제약조건은 지정할 수 없음.조건절에서 사용되어 다른 것과 비교될수 없으며 인덱스를 만들수 없음.select 문 내에서 where의 조건, group by, order by등의 각종 함수를 사용할 수 없음.계산식에서 사용될 수 없음.
    RAW and Long RAW
      RAW와 long raw datatype은 다른 시스템으로 상호 convert 되지 않는 data 에 사용.long raw 는 graphics,sound,documents,arrays of binary data를 저장하는데 사용.long raw는 2Gbytes 까지 저장이 가능하고, raw는 255bytes까지 저장.long raw는 인덱스가 불가능하고 raw 는 인덱스가 가능.raw나 long raw와 char 상호 자동 convert 되며 binary data는 hexadecimal form 으로 표현.* long raw의 경우는 2Gbytes나 되기 때문에 인덱스를 한다면 많은 시간과시스템 부하를 초래.
    ROWID and ROWID datatype
      실제 row가 존재하는 테이블에는 rowid가 없으며 인덱스에만 rowid가 존재.non-clustered table 에 존재하는 각 row는 physical 한 address에 대한 unique 한 rowid가 존재.clustered table의 경우에는 같은 data block에 존재하는 다른 table의 row는 같은 rowid 를 가질수 있음.row에 할당된 rowid는 import나 export utility를 사용하여 import나 export 되지 않는 한 변경되지않음.table 로부터 row를 삭제할 때 그 row에 할당된 rowid는 다음에 insert되는 row에 할당됨.rowid는 database 에 저장되지도 않고, database data도 아님.
    MLSLABEL datatype
      trusted oracle에서 제공.이 datatype 은 binary format의 operating system label을 저장할때 사용.data dictionary에 있는 binary label에 대한 map을variable-length tag 형태로 저장.(row당 2~5bytes)binary label 대신 representative tag로 저장되는 것은 binary operating system label이 매우 크기 때문. (space 사용에 효과적.)
      4. DATA conversion
    여러 function 을 이용하여 오라클은 자동으로 datatype을 convert한다.
    RULE 1: Assignment
      assignment에 의하여 오라클은 자동으로 다음을 convert 한다.varchar2 or char to numbernumber to varchar2varchar2 or char to date· date to varchar2· varchar2 or char to rowid· rowid to varchar2· varchar2 or char to label· label to varchar2· varchar2 or char to hex ② RULE 2 : Expression evaluation- expression evaluation에 의하여 오라클은 자동으로 다음을 convert한다.· varchar2 or char to number· varchar2 or char to date variable :=expression 의 경우 오라클은 먼저 rule2를 사용하여expression을 계산. 성공적으로 계산이 되면 하나의 value값이 나오고datatype을 가짐. 이 다음에 rule1을 사용하여 이 value 값을assignment's target에 할당하려고 함.* char to number conversion은 character string이 유효숫자를 가질 때만가능. char to date 역시 character string이 date 기본 format인DD-MON-YY를 가질 때 가능.
      5. 데이타 타입의 동격화(Datatype Equivalencing)
    예를 들어 VARCHAR변수가 있다. 이 변수는 C의 Structure구조로 되어 있기 때문에 Embedded SQL을 제외하고 일반 C언어에서 VARCHAR로 선언된 호스트 변수를 참조하려면 구조체(Structure)형식으로 참조를 해야만 한다. VARCHAR경우에는 내부적으로 아래와 같이 구성되어 있다.
      typedef struct { unsigned short len; unsigned char arr[1]; } VARCHAR;/* VARCHAR형으로 선언된 호스트 변수의 실제모습 */VARCHAR user_name[20];struct { unsigned short len; /* 호스트 변수의 길이 저장 */ unsigned char arr[1]; /* 호스트 변수 데이타 저장 */} user_name;
    그렇기 때문에 VARCHAR형으로 선언된 호스트 변수는 실제 데이타가 있는 부분(arr[])과 호스트변수가 포함하는 문자열의 길이(len)을 포함한다.실제로 이 호스트 변수를 참조하는 방법은
      strcpy((char *) user_name.arr, "EDU");user_name.len = strlen(user_name.arr);
    VARCHAR로 선언된 호스트 변수를 데이타베이스에 사용 시출력용일 때 : SELECT INTO문에서는 구조체내의 arr과 len에는 데이타 베이스의 값이 저장되어 출력된다. 사용자는 참조만 하면 된다.입력용일 때 : 조건절(WHERE절)에서 사용, INSERT, UPDATE에서 사용하여 정확한 답을 얻으려면 길이(LEN)를 지정해 주어야만 한다.우리가 Pro*C프로그램에서 자주 부딪치는 부분중의 하나이다.이런 문제 해결을 위해서 데이타 타입의 동격화가 있다. (Data Equivalencing)STRING으로 동격화 시켜주는 것이다.데이타 타입의 동격화의 문법과 예는 아래에 있다.
      데이타 타입의 동격화(Datatype Equivalencing)의 사용
    데이타 타입 동격화는 오라클이 입력 데이터의 해석 방법을 프로그래머가 원하는 데로 변경시키는 것이다.
      EXEC SQL VAR 호스트 변수명 IS 외부데이타타입[(길이:길이, 소숫점이하 길이)]];EXEC SQL BEGIN DECLARE SECTION; char emp_name[11]; EXEC SQL VAR emp_name IS STRING(11); char emp_job[11]; EXEC SQL VAR emp_job IS STRING(11); char emp_ename[100][11]; EXEC SQL VAR emp_ename IS STRING(11); /* ARRAY 변수 정의 */EXEC SQL END DECLARE SECTION;
    선언된 하나 하나의 호스트 변수마다 동격화를 시킬 수 있고, Pro*C에서는 user defined datatype으로 외부 테이타타입으로 한번에 변경시킬 수 있다.
      EXEC SQL TYPE 사용자정의타입 IS 외부데이타타입 [(길이)] [REFERENCE];typedef char asciz[350];EXEC SQL BEGIN DECLARE SECTION; EXEC SQL TYPE asciz IS STRING(350) REFERENCE; asciz catalog_cd[100]; /* ARRAY 변수 정의 */ asciz factor_cd1; asciz factor_cd2; asciz factor_cd3; asciz factor_cd4; asciz factor_cd5;EXEC SQL END DECLARE SECTION;
      6. PreProcessor의 사용
    C에서 사용된 문법으로 PreProcessor시에 참조되어 포함 또는 포함되지 않는 값들을 나타낸다.
      #define : 매크로를 정의한다.#include : 현위치에 문장 다음에 나오는 화일을 대치시킨다.#ifdef : 뒤에 따라오는 상수가 이전에 정의되어 있으면 문장 이후에 나오는 source코드를 포함하여 컴파일한다.#ifndef : 뒤에 따라오는 상수가 이전에 정의되지 않았으며 문장 이후에 나오는 source 코드들을 컴파일에 포함시키지 않는다.#endif : #ifdef, #ifndef의 끝을 나타낸다.#elif : #ifdef, #ifndef의 다음 조건을 나타낸다.<예>#define NAME_LEN 20#define PASS_LEN 20VARCHAR uname[NAME_LEN];VARCHAR passwd[PASS_LEN];
      7. 구조체 변수의 사용
    Pro*C 2.0이상에서는 구조체 형식의 호스트 변수를 사용할 수 있다.이렇게 사용함으로써 일일이 호스트 변수를 열거하지 않아도 된다.선언
      #define UNAME_LEN 20struct { VARCHAR emp_name[UNAME_LEN] float salary; float commission;} emprec;
    사용(SELECT .. INTO)
      EXEC SQL SELECT ename, sal, comm INTO :emprec FROM EMP WHERE EMPNO = :emp_number;
      8. Array 호스트 변수의 사용
    데이타베이스를 ACCESS속도를 향상시킨다.
      char emp_name[10][50]; int emp_number[50]; double salary[50];
    예를 들어 300건의 자료를 테이블에 INSERT할 경우 ARRAY를 사용하지 않으면 300번의 INSERT가 발생하게 된다. 만약 ARRAY를 사용하면 1번의 INSERT문만 실행시키면 된다.
      int hi_lo_scores[25][25];
    쉽게 프로그래밍 할 수 있다.
      ARRAY변수의 선언
    위와 같이 선언하면 된다. 아래와 같은 2차원 array는 허용되지 않는다.
      char emp_name[20][50]; int emp_number[50]; double salary[50];EXEC SQL SELECT ENAME, EMPNO, SAL INTO :emp_name, :emp_number, :salary FROM EMP WHERE SAL > 1000;
    INSERT, UPDATE, DELETE문장의 입력 변수에 호스트 Array를 사용할 수 있고, SELECT나 FETCH의 INTO절의 출력 변수에 사용할 수 있다.호스트변수를 사용하는 것과 ARRAY호스트 변수를 사용하는 것은 기본적으로 같으나,한가지 다른점은 ARRAY변수를 사용할 경우, 선택적으로 “FOR”절을 사용해야 한다.그리고 호스트변수와 ARRAY변수를 같은 문장에 사용하여서는 안된다.SELECT ... INTO문에서의 사용
      SELECT ... INTO 문에서 사용시에는 리턴되는 데이타의 최대갯수를 알고 있어야 하고 그 최대 갯수 만큼의 ARRAY를 선언해야 한다.위의 예에서 50개보다 많은 ROW가 리턴된다면 50개 이상의 데이타는 구할 수 없게 된다.다시 SELECT .. INTO문을 실행한다면 또 다시 처음 50개의 ROW만 구해질 것이다.동시에 ORACLE에러가 발생한다.ORA-02112: PCC: SELECT ... INTO return too many rows;
    FETCH ... INTO 문에서의 사용
      int emp_number[20];float salary[20];EXEC SQL DECLARE emp_cursor CURSOR FOR SELECT empno, sal FROM emp;EXEC SQL OPEN emp_cursor;EXEC SQL WHENEVER NOT FOUND do break;while(1){ EXEC SQL FETCH emp_cursor INTO :emp_number, :salary; /* fetch된 row의 작업 */ ....}FETCH된 ROW의 갯수sqlca.sqlerrd[2]에 저장되어 있다. 이 값은 각 fetch되는 cursor에 누적된 값이다.EXEC SQL OPEN cursor1;EXEC SQL OPEN cursor2;EXEC SQL FETCH cursor1 INTO :array_of_20;sqlca.sqlerrd[2]의 값 : 20EXEC SQL FETCH cursor2 INTO :array_of_20;sqlca.sqlerrd[2]의 값 : 20 40이 아님.EXEC SQL FETCH cursor1 INTO :array_of_20;sqlca.sqlerrd[2]의 값 : 40EXEC SQL FETCH cursor2 INTO :array_of_30;sqlca.sqlerrd[2]의 값 : 50
    INSERT문에서의 사용
      호스트 ARRAY를 INSERT문의 입력변수로 사용할 수 있다. char emp_name[20][50];int emp_number[50];float salary[50];EXEC SQL INSERT INTO EMP (ENAME, EMPNO, SAL) VALUES(:emp_name, :emp_number, :salary);위에서는 한번의 INSERT문으로 50개의 ROW가 EMP테이블에 추가되었다.ARRAY의 데이타 전체가 유효하지 않다면 “FOR”절을 사용하여 데이타를 선택적으로 INSERT할 수 있다.
    UPDATE문에서의 사용
      호스트ARRAY를 UPDATE문의 입력변수로 사용할 수 있다.int emp_number[50];float salary[50];EXEC SQL UPDATE emp SET sal = :salary WHERE EMPNO = :emp_number;ARRAY호스트 변수 중 유효하지 않은 것이 존재하면 "FOR"절을 사용하여 유효한 것만 UPDATE시킬 수 있다.
    DELETE문에서의 사용
      int emp_number[50];EXEC SQL DELETE FROM emp WHERE empno = :emp_number;
    Indicator Array변수의 사용
      int emp_number[50];int dept_number[50];float commission[50];short ind_comm[50];EXEC SQL INSERT INTO emp (empno, deptno, comm) VALUES (:emp_number, :dept_number, :commission INDICATOR :ind_comm);Indicator변수의 array와 호스트변수의 array는 같아야 한다.
    FOR절의 사용
      INSERT, EXECUTE, FETCH, DELETE, OPEN, UPDATE 등에서 ARRAY호스트 변수를 사용할 경우 선택적으로 "FOR"절을 사용할 수 있다.특히 INSERT, DELETE, UPDATE문에서는 유용하다.char emp_name[100];short salary [100];int rows_to_insert;rows_to_insert = 25;EXEC SQL FOR :rows_to_insert INSERT INTO emp (ename, salary) VALUES (:emp_name, :salary);/* 100개의 row중에 25개만 insert했다. */"FOR"절은 UPDATE와 INSERT가 동시에 발생되는 TRANSACTION에서는 구현하기가 쉽다.ARRAY호스트 변수를 사용하면서 선택적으로 INSERT, UPDATE해야 하는 프로그램에서는 "FOR"절이 유용하게 사용된다.
      9. Structure Array 의 사용
      호스트 변수로 Structure Array를 사용할 수 있다.struct { char emp_name[11]; int emp_number; int dept_number;} emp_rec[3];.......EXEC SQL SELECT ename, empno, deptno INTO :emp_rec[1] FROM emp;.....
      10. Indicator변수의 사용
      INDICATOR변수는 2바이트 정수형으로 선언되어야 하고 SQL문장에서는 ":"을 앞에 붙여 호스트변수의 바로 뒤에 기술한다.INDICATOR변수는 컬럼의 상태를 가지고 있다.-1 : 선택된 컬럼이 NULL이다.EXEC SQL BEGIN DECLARE SECTION; int emp_number; float salary, commission; short comm_ind;EXEC SQL END DECLARE SECTION;EXEC SQL SELECT SAL, COMM INTO :salary, :commission:ind_comm FROM EMP WHERE EMPNO = :emp_number;if(ind_comm == -1 ) /* commission 컬럼이 NULL이다. */ pay = salary;else pay = salary + commission;
    호스트 Indicator Structure변수의 사용
      Indicator변수를 구조체 형식으로 사용할 수 있다.struct { char s_name[32]; int s_id; char grad_date[9];} student_rec;struct { short s_name_ind; short s_id; short grade_date_ind;} student_rec_ind;EXEC SQL SELECT S_NAME, S_ID, GRADE_DATE INTO :student_rec:student_red_ind FROM STUDENT_LIST WHERE S_ID = '95034024';
    중첩된 Structure구조의 변수는 사용하지 못한다.
    출처 : http://blog.naver.com/nsjung74/110007853683

    'Oracle' 카테고리의 다른 글

    Dynamic SQL의 사용  (0) 2007.01.21
    SQL문 기본  (0) 2007.01.21
    proc 파헤치기  (0) 2007.01.21
    LINUX + ORACLE 10g 10.1 Install  (0) 2006.06.11
    Installing Oracle9iR2(9.2.0.4) on RH AS4  (0) 2006.06.11
    , .

    proc 파헤치기

    Oracle 2007. 1. 21. 17:07

    1절. 소개

    이번장에서는 Proc 프로그래밍을 좀더 깊이 있게 다루어 보도록 하겠다. Proc 프로그래밍 환경은 이미 다 갖추어져 있으며, proc 가 무엇인지도 개념을 잡고 있다고 가정하고 강좌를 진행할 것이다. sql 역시 기본적으로 사용할줄 아는걸로 가정하겠다.

    만약 위의 내용들이 준비되어 있지 못하다면 proc 프로그래밍(1)오라클 817 설치하기 문서를 먼저 읽어 보기 바란다.

    이외에도 Proc 와 직접적인 관련은 없지만 termios 를 이용한 터미널 제어와 ANSI 를 이용한 화면조정에 대한 내용도 코드를 통해서 약간 다루게 될것이다. termios 는 조만간 자료를 만들어서 올릴 생각이니, 이 문서에서는 그냥 이러한 도구를 이용해서 터미널 제어가 가능하구나.. 하는 정도로만 알아두길 바란다.


    2절. proc 프로그래밍의 기본

    2.1절. proc 문의 구조

    기본적으로 proc 는 C 코드와 함께 쓰이도록 되어 있다. 이를테면 C 코드안에 SQL 문을 포함(embedded) 시키는 일을 한다. 그럼으로 proc 가 구조적으로 가져야될 가장 중요한 특징은 바로 (oracle)sql 과 C 프로그램과의 데이타 교환이 될것이다.

    proc 는 C 와의 데이타 교환을 지원하기 위해서 4가지 큰 구조로 나뉜다. 하나는 Executable 영역이며, 다른 하나는 Declarative 영역이다. 또한 PL/SQL 블럭을 추가 시킬수 있으며, SQL 명령의 실행 상태를 측정하기 위함 Indicator Variables 등을 사용할수 있다.


    2.1.1절. Executable 영역

    Executable 이라는 어감에서 알수 있듯이, Executable 은 SQLLIB 를 실행시간에 호출하기 위해서 사용되는 영역이다. SQLLIB 를 호출함으로써 C(혹은 C++)로 된 코드에서 오라클 SQL 을 실행하고 때에 따라서는 SQL 문에 C 에서 선언한 값을 입력하거나 혹은 SQL 쿼리 결과를 C 에서 선언한 변수에 출력할수 있게 된다.

    Executable 영역은 오라클 에서 데이타베이스 관리를 위해서 사용하는 표준 SQL 과 확장(오라클에서 추가한) SQL 문을 실행한다. 즉 테이블을 생성하거나 CREATE, 지우고 DROP, 권한 설정을 하고 GRANT, 값을 가져오거나 SELECT, 값을 지우는 DELETE 등의 일을 처리하게 된다. SQL 문을 C 코드에 embeded 시키기 위한 영역이라고 생각하면 된다.

    다음은 Executable 영역에서 다룰수 있는 SQL 관련 실행문이다. 이 문서는 ORACLE SQL 자체에 대한 강의문서는 아님으로 이러한 일들을 할수 있다라는 정도로 열거만 하도록 하겠다. 조금이라도 SQL 을 다루어 보았다면 대부분 무슨일을 하는 명령어인지 이해될것이다.

    CLOSE, CONNECT, CREATE, DROP, FREE, GRANT, AOAUDIT, RENAME, TRUNCATE, DELETE, EXPLAIN PLAN, FETCH, INSERT, LOCK TABLE, OPEN, SELECT, UPDATE, COMMIT(트랜잭션관리), ROLLBACK, SAVEPOINT, SET TRANSACTION, DESCRIBE(dynamic sql 용), EXECUTE, PREPARE, ALTER SESSION(세션 제어용) 
    위의 명령어들은 다시 Interactive 한것과 그렇지 않은 것 (no Interactive)으로 나뉜다. 인터엑티브란 SQL문 실행결과와 C프로그램간의 데이타 교환이 있는 것을 말하며, no 인터엑티브란 SQL 문만 단독으로 실행되며 C 프로그램과의 데이타 교환이 없는걸 말한다. no Interactive 한 문으로는 CONNECT, FETCH, OPEN, DESCRIBE, EXECUTE, PREPARE 가 있다. - 나머지는 모두 C코드와 인터엑티브 하게 작용(상호작용)한다 - 복잡하게 생각할 필요 없이 그냥 상식적으로 생각하면 된다. 오라클과 연결하고, DB 를 OPEN 하는데는 C코드와 얘기할 필요가 전혀 없을 것이다. 그냥 연결하고 오픈하면 되기 때문이다. 반면 SELECT 의 경우 오라클에서 SELECT 한 결과를 C 프로그램에 되돌려주어야 함으로 interactive 하게 작용할 필요가 있다.

    interactive 하게 사용하기 위해서보통 ":" 을 사용하게 된다. 예를들어서 오라클 DB 에서 셀렉트한 결과를 C 프로그램의 변수에 저장하길 원한다면 아래와 같은 방법으로 사용하면 된다.

    char zipcode[12];EXEC SQL SELECT zipcode          INTO : zipcode[12]          FROM zipcode where zipcode_no = "500-180"; 
    C 프로그램에서 알아와야 될 값은 SELECT 로 가져오게 되는 zipcode 값이다. 이것을 C 프로그램에서 선언한 zipcode 로 넘겨주기 위해서(INTO) ":" 를 사용하고 있음을 알수 있다.


    2.1.2절. DECLARATIVE 지원

    기본적으로 C 의 자료형과 SQL 에서 다루는 자료형은 서로 호환되지 않는다.

    그럼으로 이들의 호환을 보장해줄수 있어야 한다. 해서 proc 는 별도의 선언(Declarative) 영역을 두어서, 선언을 하게 하고 proc 프리컴파일러를 돌려서 나중에 C 코드와 호환가능 하도록 변환하는 정책을 사용하고 있다.


    2.1.3절. Embedded PL/SQL Blocks

    proc 는 PL/SQL 블럭을 C 코드상에서 사용할수 있도록 도와준다. PL/SQL 블럭을 추가하기 위해서 단지 EXEC SQL EXECUTE 와 END-EXEC 만을 사용하면 된다.

    PL/SQL 은 기본적으로 모든 SQL 데이타를 제어할수 있도록 지원하며, 아울러 트랜잭션까지도 해결해준다. 그럼으로 훨씬 안정성있고, 유지 관리 편한 코드를 만들수 있도록 도와 준다.


    2.1.4절. host 변수와 indicator 변수

    Host 변수는 오라클과 어플리케이션(C/C++ 로된) 사이의 통신(데이타 교환)을 위해서 사용된다. 이들 변수는 C 코드 상에서 생성되며, 선언된 변수는 C 와 공유할수 있게 된다.

    host 변수는 크게 input host 변수와 output host 변수가 있는데, input host 변수는 프로그램 데이타를 Oracle 에 넘겨주기 위해서 사용되며, output host 변수는 오라클의 데이타(쿼리 결과등)을 프로그램에게 넘겨주기 위해서 사용한다. 이러한 호스트변수의 사용은 오라클문장에 ":" 를 이용함으로써 사용가능하게 된다.

    또한 indicator 변수를 사용할수도 있는데, indicator 란 뜻에서 생각할수 있듯이 오라클문의 실행결과를 측정하기 위한 용도로 사용한다. 이를테면 CONNECT 를 통해서 ORACLE DB 서버로 연결을 시도했을때의 성공혹은 실패에 대한 리턴값이라고 보면 될것이다. 좀더 기술적으로 말하자면 indicator 변수는 host 변수의 상태를 측정하기 위한 용도로 상요된다.


    2.1.5절. Cursor 과 Fetch 의 지원

    fetch 라면 특히 php+mysql 을 이용한 웹플밍 작업을 하면서 많이 다루어 보았을것이다. proc 에서는 쿼리결과물(리스트) 의 관리를 위해서 Cursor 과 Fetch 를 지원한다.


    2.2절. 오라클의 데이타 타입

    proc 프로그래밍의 일반적인 방법은 C 프로그램에서 input host 변수를 통해서 ORACLE 측에 데이타를 요청하면, ORACLE 데이타베이스는 output host 변수를 통해서 C 프로그램에 데이타를 되돌려 주는 방식을 사용한다. 그러므로 오라클은 반드시 C 프로그램과의 통신에 사용되는 데이타의 타입에 대해서 알고 있어야만 한다.

    오라클은 interanl 과 external 2가지의 데이타 타입을 인식한다. interanl 데이타 타입은 오라클 데이타베이스에서 각각의 칼럼의 데이타 타입을 지정하기 위해서 사용하는 데이타 타입이다.

    external 데이타 타입은 host 변수를 통해서 저장될 데이타의 타입을 말한다. 만약 C 프로그램에서 input host 변수를 통해서 오라클에 데이타를 전달했다면, 오라클은 이 변수를 external 데이타로 간주하고 이것을 오라클자신이 사용하는 internal 데이타 타입과 일치시켜서 작업을 하게 된다. 마찬가지로 작어을 마치고 데이타를 되돌려 줄때도 internal 데이타 타입을 external 데이타 타입으로 변경시킨후 output host 변수에 저장해서 되돌려 주게 된다. 이러한 복잡한 데이타 변환작업이 일어나는 이유는 C 프로그램에서 사용하는 데이타 타입과 오라클에서 사용하는 데이타 타입이 근본적으로 서로 다르기 때문이다. 내부적으로 보자면 proc 는 이러한 데이타 타입의 일치를 위해서 void * 형변환을 이용한다.

    proc 는 호스트 변수로 배열을 사용할수 있도록 지원하며, 마찬가지로 구조체도 지원한다. 이러한 배열/구조체 가 사용될수 있는 곳은 SQL 문을 사용할경우이다. 즉 SELECT, FETCH, DELETE, INSERT, UPDATE 등에 사용할수 있다.


    2.3절. Transaction

    오라클에서 Transaction 은 매우 중요한 요소이다. Transaction 은 이를테면 데이타의 무결성을 검증시켜주기 위해서 SQL 상태를 논리적인 하나의 상태로 관리하는 것이라고 볼수 있다.

    oracle 은 transaction 을 유지하기 위해서 COMMIT 와 ROLLBACK 를 이용하는데, proc 에서도 마찬가지로 COMMIT, ROLLBACK 를 그대로 이용해서 트랜잭션을 처리할수 있도록 도와준다. 이러한 작업은 특히 PL/SQL 구문을 이용함으로써 C 코드상에 쉽게 임베디드 시킬수 있다. 아래는 Executable SQL문을 이용해서 어떻게 트랜잭션처리를 할수 있는지를 벼여준다.

    ...EXEC SQL   UPDATE zipcode    SET dong =: mdong   WHERE bunji =: mbungiif (sqlca.sqlcode == 0)    EXEC SQL COMMIT WORKelse     EXEC SQL ROLLBACK WORK;... 


    2.4절. Error 제어

    제대로된 프로그램은 제대로된 에러처리 루틴을 가진다. proc 는 WHENEVER 문을 통해서 ORACLE 에서의 작업중 발생한 문제를 C 어플리케이션에서 알수 있도록 도와준다.

    이것은 단지 SQLCA 를 include 시키는 것으로 가능하며, 에러를 체크해야될 부분에서 간단하게 사용할수 있다. 예를들어 오라클 서버에 연결을 시도하고 연결 시도 결과를 체크하고 싶다면, 아래와 같은 간단한 방법으로 에러를 제어할수 있다.

    EXEC SQL INCLUDE SQLCA;....int main(){    ....    EXEC SQL CONNECT :userid;    // 에러 검사    if (sqlca.sqlcode < 0)    {        // 자세한 에러메시지 출력        printf("%s\n", sqlca.sqlerrm.sqlerrmc);        exit(0);    }} 


    2.5절. Proc를 이용한 어플리케이션 개발방법

    전체적으로 보자면 다음과 같은 방법을 통해서 Proc 개발이 이루어진다.

    그림 1. Proc를 이용 오라클 DB프로그래밍 과정

    보면 알겠지만 일반적인 C 어플리케이션 개발방법과 비교해서 "Proc 코드작성", "Precomplie" 가 들어간것만 빼고는 동일하다는걸 알수 있을 것이다.


    3절. 셈플작성

    가장 빠른 이해를 위해서는 역시 셈플 작성만한게 없다. 이미 모든 테스트 환경은 가추어져 있다고 가정을 하고 셈플을 작성할 것이다. 셈플 프로그램은 "우편주소 검색" 프로그램이다.

    셈플프로그램은 모듈별로 분할되어서 Makefile 로 관리 될것이며, 헤더 파일은 include 라는 서브디렉토리를 만들것어서 관리하게 된다. 다음은 이번 예제의 쏘쓰 트리구성도이다.

     +--/---+--- Makefile      make 파일        |        +--- main.pc       main 함수를 포함        |        +--- myterm.pc     teminal 제어 관련 함수        |        +--- zipcode.pc    DB연결및 쿼리 관련        |        +--- include ----+-- menu.h     메뉴들                          |                         +-- myterm.h                           |                         +-- zipcode.h 

    셈플 어플리케이션은 사용자와의 인터페이스를 위해서 ANSI 와 termios 를 조합해서 사용할것이다. ANSI 는 출력의 모양 - 커서이동, 화면 정리 - 을 조정하기 위해서 사용되며, termios 는 터미널 특성(입출력) 을 제어하기 위해서 사용될것이다.

    예를들어서 보통 패스워드 입력을 위해서는 패스워드를 화면에 출력하지 않고 "*" 로 대치시켜서 출력하게 된다. 이러한 기능은 termios 의 터미널특성 제어를 통해서 구현하게 된다. termios 는 별도의 문서를 이용해서 자세히 설명하도록 할것이다.

    ANSI 는 커서의 움직임과 화면지우기, 라인지우기 등의 구현을 위해서 사용한다.


    3.1절. Makefile

    아주 간단하다. 분석하는데 어려움이 없을것이다.

    TARGET          = zipcodeCC              = gccPROC            = procLIB             = -L$(ORACLE_HOME)/lib -lclntshMYINC           = include/PROCINC         = include=$(ORACLE_HOME)/precomp/public/ include=$(ORACLE_HOME)/rdbms/demo/ \    include=$(ORACLE_HOME)/rdbms/public/ \    include=$(ORACLE_HOME)/network/public/ CINC            = -I$(ORACLE_HOME)/precomp/public/ -I$(ORACLE_HOME)/rdbms/demo/ \    -I$(ORACLE_HOME)/rdbms/public/ -I$(ORACLE_HOME)/network/public/ ORA_OPT         = PARSE=NONE RELEASE_CURSOR=YES MODE=ANSICC_OPT          =OBJECT          = main.o \                zipcode.o \                myterm.oORA_GARBAGE     = *.dcl *.cod *.cud *.lis######## implicit rules.SUFFIXES: .pc .c.pc.c:    $(PROC) $* INCLUDE=$(MYINC) $(PROCINC) $(ORA_OPT).c.o:    $(CC) -c -o $*.o $*.c -I $(MYINC) $(CINC)####### build rulesall:            $(TARGET)$(TARGET):      $(OBJECT)    $(CC) -o $(TARGET) $(OBJECT) $(LIB)main.c: main.pcmain.o: main.c zipcode.c myterm.czipcode.c : zipcode.pczipcode.o : zipcode.cmyterm.c : myterm.pcmyterm.o : myterm.cclean:    rm -f $(TARGET) $(OBJECT) $(ORA_GARBAGE) *.c 


    3.2절. main.pc

    #include <unistd.h>#include <stdio.h>#include <zipcode.h>#include <myterm.h>#include <termios.h>int main(){    /* 터미널 초기화 */      termio_init();    /* 로그인 */      if (login(3) < 0)    {        login_error();        exit(0);    }        /* 로그인에 성공했다면     * 실제 작업에 들어간다.      */    search_zipcode();    /* 최초 터미널 상태로 복원시킨다 */      termio_default();    return 1;} 


    3.3절. myterm.pc

    #include <unistd.h>#include <stdio.h>#include <zipcode.h>#include <myterm.h>/* * 터미널 초기화 */void termio_init(){    tcgetattr(0, &stored_settings);    default_settings = stored_settings;    tcsetattr(0, TCSANOW, &default_settings);    stored_settings.c_lflag &= (~ICANON);    tcsetattr(0, TCSANOW, &stored_settings);}void termio_default(){    tcsetattr(0, TCSANOW, &default_settings);}/* 패스워드를 화면에 보이지 않기 위해서 * 입력을 화면에 반향(echo) 하지 않도록 설정한다. */void echo_off(){    struct termios new_settings;    tcgetattr(0, &stored_settings);    new_settings = stored_settings;    new_settings.c_lflag &= (~ECHO);    tcsetattr(0, TCSANOW, &new_settings);    return;}/* * 기본 터미널 상태로 되돌린다. */void echo_on(){    tcsetattr(0, TCSANOW, &stored_settings);    return ;} 


    3.4절. zipcode.pc

    실질적으로 오라클데이타 베이스와 관련된 작업을 하는 함수들은 여기에 정의되어 있다. 그리 복잡하지 않으니 대충 훑어봐도 이해 가능할것이다.

    #include <stdio.h>#include <zipcode.h>#include <myterm.h>#include <menu.h>EXEC SQL INCLUDE SQLCA;/* * 패스워드를 받아들인다. * echo_off 함수를 호출해서 * 키보드입력이 반향되지 않도록한후 * 키입력을 "*" 로 대체한다. * 입력을 마친후에는 echo_on 함수를 호출하여 * 입력을 반향한다. */void get_pass(char *pass){    char buf;    int i = 0;    echo_off();    while ((buf=getc(stdin)) != '\n')    {        pass[i] = buf;        printf("%c", '*');        i++;    }    echo_on();    return ;}/* * 단일 문자를 입력받기 위해서 사용한다. * getc 를 이용한 단일 문자 입력시 * 개행문자가 반향되지 * 않도록 echo_off 함수를 호출한다. */int ngetc(){    char buf;    echo_off();    buf = getc(stdin);    if (buf != '\n')        printf("%c", buf);    echo_on();    return buf;}/* * 여러줄의 입력을 받기 위해서 사용한다. * 개행문자는 제거한후 되돌려준다. */void get_input(char *str){    char buf;    int i = 0;    while ((buf=getc(stdin)) != '\n')    {        str[i] = buf;        i++;    }    return ;}/* * 우편번호를 출력한다. * 실제 검색은 dong 만을 가지고 한다. */int print_zipcode(char *city, char *dong){    int state;    int i;    int running = 1;    /*     * DECLARE 영역     */    EXEC SQL BEGIN DECLARE SECTION;        /*         * Select 한 데이타가 들어갈 구조체이다.          * 주의해야 할점은 각 멤버변수의 크기를          * 잡을때 실제 필드의 크기보다 +1 만큼 더크게          * 배열 공간을 잡아야 한다는 것이다.          * 실제 zipcode table 의 zipcode 필드는 7의 크기이다.         * +1 만큼 더 크게 잡는 이유는 널값을 저장하기 위함이다.            */        struct testdata        {            char zipcode[8];            char sido[11];            char gugun[15];            char bunji[19];            char dong[45];            char numb[3];        } mydata;        char mdong[16];        int page = 1;        int page_per_list = 17;        int start_listnum, end_listnum;    EXEC SQL END DECLARE SECTION;    /*     * 문자열 copy 를 통해서 dong 변수를     * declare 영역에서 선언된 오라클 변수로 복사한다.     */    strcpy(mdong, dong);    strcat(mdong,"%");    while(running)    {        int i;        /* 주소리스트 영역 (5-17 라인)을 지운다 */        SCR_CLEAR2(5,17);        MOVE_CURSOR(5, 1);        /* 출력하고자 하는 주소리스트 영역을 계산한다         * page          : 보고자 하는 페이지         * end_listnum   : 현재 페이지에서 가장큰 리스트번호         * start_listnum : 현재 페이지의 시작 리스트 번호         * page_per_list : 한페이지에 보여줘야할 리스트 수 (17)         */        end_listnum = page_per_list * page;        start_listnum = end_listnum - page_per_list;        /*         * CURSOR 을 만든다.         * mysql 에서 범위지정을 위해사용하는 limit 를 오라클에서는         * 제공하지 않음으로, rownum 을 이용한 in-line view 를 사용한다.         */        EXEC SQL DECLARE zip_cursor CURSOR FOR            SELECT * FROM            (                SELECT ZIPCODE, SIDO, GUGUN, BUNJI, DONG, ROWNUM NUMB                FROM ZIPCODE WHERE DONG like : mdong            )             WHERE NUMB > : start_listnum            AND NUMB < : end_listnum;        printf("dong : (%s)\n", mdong);        if (sqlca.sqlcode !=0 )        {            printf("ERROR\n");            return -1;        }        /*         * 커서를 사용하기 위해서 연다.         */        EXEC SQL OPEN zip_cursor ;        /*         * 열린 커서에서 FETCH 작업중 더이상 FETCH 할         * 데이타가 없으면 DO 이후의 문인 break 를 실행한다.         */        EXEC SQL WHENEVER NOT FOUND DO break;        for (i=0; ;i++)        {            /*             * FETCH 한 데이타는 mydata 구조체에 입력한다.             */            EXEC SQL FETCH zip_cursor INTO: mydata;            /*             * proc 에서는 FETCH 한 레코드의 특정필드에 데이타가             * 없을경우 에러(-1405) 처리를 한다.              * 그러나 필드의 특성에 따라서 NULL 이 될수도 있음으로             * 이 에러는 무시하고 넘어가도록 한다.             */            if (sqlca.sqlcode < 0)            {                if (sqlca.sqlcode != -1405)                {                    break;                 }            }            /*              * 우편번호 데이타 출력              */            printf("%s %s %s %s\n",                     mydata.zipcode,                       mydata.sido, mydata.gugun,                    mydata.dong, mydata.bunji);        }        /* 페이지 출력 */        MOVE_CURSOR(22, 1);        LINE_CLEAR;        printf("page : %d", page);        /*          * 열린 커서는 더이상 사용하지 않을경우         * 닫아주어야 한다.         * 그렇지 않을경우 메모리 누수가 생길수 있다.          */        EXEC SQL CLOSE zip_cursor;        /*         * move_page 함수를 호출하여 키입력을         * 받아들여서 페이지 이동을 한다.         */        if (i == 16 || page > 1)        {            int ans;            while(1)            {                ans = move_page();                if (ans == NEXT)                {                    if (i == 16)                    {                        page++;                        break;                    }                }                else if (ans == PREV)                {                    if (page > 1)                    {                        page--;                        break;                    }                }                else                    return 1;            }        }        else        {            return 1;        }    }}/* * 로그인 * check_num 만큼 아이디와 패스워드를 묻는다. */int login(int check_num){    int loop = 1;    char id[16];    char pass[16];    SCR_CLEAR;    while(1)    {        memset(pass, 0x00, 16);        memset(id, 0x00, 16);        MOVE_CURSOR(10,5);        printf("%s\n", login_prompt);        if (loop > 1)        {            MOVE_CURSOR(15, 23);            printf("Login Failure !! %s", pass);        }        MOVE_CURSOR(12, 34);        get_input(id);        MOVE_CURSOR(13, 34);        get_pass(pass);         if ((dbconnect(id, pass) < 0))        {            if (loop == check_num)            {                return -1;            }            #ifdef __DEBUG             MOVE_CURSOR(22, 1);            printf("%s", sqlca.sqlerrm.sqlerrmc);            #endif        }        else        {            MOVE_CURSOR(22, 1);            printf("Connection Success !!");            return 1;        }        loop++;    }}/* * 아이디와, 패스워드를 이용해서 * 로그인을 실시한다.   */int dbconnect(char *id, char *pass){    EXEC SQL BEGIN DECLARE SECTION;        char loginid_pass[40];    EXEC SQL END DECLARE SECTION;        sprintf(loginid_pass, "%s/%s@oracle", id, pass);    EXEC SQL CONNECT: loginid_pass;    return sqlca.sqlcode;} /* * 동이름을 이용해서 우폄번호 검색을 한다. */ int search_zipcode(){       char city[16];    char dong[16];    int running = 1;    SCR_CLEAR;    MOVE_CURSOR(4,2);    printf("%s", hr);    MOVE_CURSOR(23,2);    printf("%s", hr);    while(running)    {        MOVE_CURSOR(1,1);        printf("%s\n", query_prompt);        memset(city, 0x00, 16);        memset(dong, 0x00, 16);        MOVE_CURSOR(2, 13);        get_input(city);        MOVE_CURSOR(3, 13);        get_input(dong);        if (strlen(city) == 0 && strlen(dong) == 0)        {            if (question_end() == YES)                running = 0;        }        else        {            MOVE_CURSOR(5, 1);            print_zipcode(city, dong);        }    }    /*     * 오라클서버와의 연결을 끊는다.     */    EXEC SQL COMMIT WORK RELEASE;    /*     * 화면을 클리어 하고 커서를     * 처음화면으로 되돌린다.     */    SCR_CLEAR;    MOVE_CURSOR(1, 1);}/* 페이지 이동 관련 */int move_page(){    char ans;    while(1)    {        MOVE_CURSOR(24, 2);        LINE_CLEAR;        printf("%s", "페이지 이동 (P:이전 N:다음 Q:종료)");        ans = ngetc();        switch(ans)        {            case('N'):            case('n'):                return NEXT;                break;            case('P'):            case('p'):                return PREV;                break;            case('q'):            case('Q'):                return QUIT;                break;        }    }}/* 종료할것인지를 묻는다 */int question_end(){    char ans;    while(1)    {        MOVE_CURSOR(24, 2);        LINE_CLEAR;        printf("%s", ques_end);          ans = ngetc();        switch(ans)        {            case('y'):            case('Y'):                return YES;                break;            case('n'):            case('N'):                return NO;                break;            default:                break;        }    }}int login_error() {    MOVE_CURSOR(23, 1);    printf("Login failure!!\n");    return -1;} 


    3.5절. include/menu.h

    메뉴와 관련된 변수들이 선언되어 있다.

    #ifndef _MENU_H_#define _MENU_H_#define SCR_CLEAR printf("^[[2J")#define MOVE_CURSOR(x,y) printf("^[[%d;%dH", x,y)#define WAIT_INPUT(x) printf("%s", x); getchar()#define chop(str) str[strlen(str)-1] = '\0'#define LINE_CLEAR printf("^[[K")#define SCR_CLEAR2(x, y) for (i=0; i < y; i++) \{ \    MOVE_CURSOR(x+i, 1);\    printf("^[[2K");\}\MOVE_CURSOR(x, 1);#define STDIN 0#define YES 1#define NO  0 #define UNKNOWN 2 #define NEXT 1#define PREV 0#define QUIT 2char *login_prompt ="                    +----------+-----------------+                    | 아 이 디 | ____________    |                    | 패스워드 | ____________    |                    +----------+-----------------+                    |                            |                    +----------+-----------------+";char *query_prompt =" 도시이름 : __________ 동 이 름 : __________";char *hr ="=============================================================================";char *question = "선택 (Y,N,X) : ";char *ques_end = "종료하시겠습니까 (Y/N) ? ";#endif 


    3.6절. myterm.h

    myterm.pc 함수에 대한 선언

    #ifndef _MYTERM_H_ #define _MYTERM_H_#include <termios.h>static struct termios stored_settings;static struct termios default_settings;void termio_init();void termio_default();void echo_off();void echo_on();#endif 


    3.7절. zipcode.h

    zipcode.pc 함수에 대한 선언

    #ifndef _ZIPCODE_H_#define _ZIPCODE_H_void get_pass(char *pass);int ngetc();int login(int);int dbconnect();int search_zipcode();int question_end();void get_input(char *str);print_zipcode(char *city, char *dong);int login_error();#endif 


    4절. 테스트

    위의 어플리케이션을 실행하면 다음과 같은 화면들을 보여줄것이다. 참고로 도시이름검색은 하지 않고 단지 "동이름" 으로만 검색한다.

    로그인

                        +----------+-----------------+                    | 아 이 디 | system______    |                    | 패스워드 | *******_____    |                     +----------+-----------------+                    |                            |                    +----------+-----------------+ 

    검색

     도시이름 : __________ 동 이 름 : 역삼______ =============================================================================dong : (역삼%)135-706 서울       강남구         역삼1동 공무원연금관리공단                  135-703 서울       강남구         역삼1동 과학기술회관                        135-707 서울       강남구         역삼1동 남영빌딩                            135-977 서울       강남구         역삼1동 로담코빌딩                          135-709 서울       강남구         역삼1동 빅토리아빌딩                        135-979 서울       강남구         역삼1동 삼부빌딩                            135-980 서울       강남구         역삼1동 삼성역삼빌딩                        135-751 서울       강남구         역삼1동 삼성제일빌딩                        135-768 서울       강남구         역삼1동 삼일프라자오피스텔                  135-711 서울       강남구         역삼1동 삼흥빌딩                            135-917 서울       강남구         역삼1동 성지하이츠1차빌딩                   135-717 서울       강남구         역삼1동 성지하이츠3차빌딩                   135-984 서울       강남구         역삼1동 스타타워                            135-718 서울       강남구         역삼1동 아가방빌딩                          135-978 서울       강남구         역삼1동 아주빌딩                            135-748 서울       강남구         역삼1동 여삼빌딩                            page : 1 ============================================================================= 페이지 이동 (P:이전 N:다음 Q:종료) 
    N/n, P/p 를 이용해서 페이지 이동이 가능하다.


    5절. 결론

    이상 proc 플밍에 대한 좀더 깊이 있는 내용을 다루어 보았다. 그러나 여기에서 다룬 내용은 전체 proc 내용에 비하면 정말 맛보기정도 이다. 말했듯이 proc 는 그 자체만으로도 책몇권분량이 쉽게 나오는 방대한 분량이다. 또한 PL/SQL 에 대한 내용도 어느정도 알고 있어야 한다.

    이문서는 어디까지나 부담없이 proc 플밍을 접할수 있도록 하기 위한 지침서 이다. (일단 컴파일 할줄은 알아야 깊이 들어가든지 말든지 할테니까)

    proc 플밍에 대한 더욱 깊은 내용은 각자의 몫이 될것이다.

    출처 : http://blog.naver.com/tipster2/100012807885

    'Oracle' 카테고리의 다른 글

    SQL문 기본  (0) 2007.01.21
    Pro*C에서 변수의 사용  (0) 2007.01.21
    LINUX + ORACLE 10g 10.1 Install  (0) 2006.06.11
    Installing Oracle9iR2(9.2.0.4) on RH AS4  (0) 2006.06.11
    Redhat 7.2 + Oracle 9i 설치하기  (0) 2006.06.11
    , .

    insert 프로그램

    MySQL 2006. 11. 22. 12:49

    /**************************************************************
    * FileName : target.c *
    * DESC : MySQL 기본 연결 *
    * Compile : gcc -o target target.c -lmysqlclient \ *
    * -I/usr/local/mysql/include/mysql \ *
    * -L/usr/local/mysql/lib/mysql *
    * Error : 실행할 때 에러가 난다면 아래 명령어를 실행 *
    * bash : export LD_LIBRARY_PATH=/usr/local/lib/mysql *
    * csh : setenv LD_LIBRARY_PATH /usr/local/lib/mysql *
    * 실행 : ./target TableName (삽입할 개수) *
    *************************************************************/

    #include <stdio.h>
    #include <time.h>
    #include <mysql.h>

    #define HOST "localhost"
    #define USER "root"
    #define PASS "test"
    #define DB_NAME "test"

    MYSQL_RES *result;
    MYSQL_ROW row;
    MYSQL mysql;

    int main(int argc, char *argv[])
    {
    char query[1024];
    int res, i, j, num;
    time_t clock1, clock2;

    if(argc != 4){
    printf("Usage : [%s] TableName Number\n", argv[0]);
    exit(1);
    }
    /* 수행 시간을 위해 필요 */
    (void)time(&clock1);


    mysql_init(&mysql);

    if(!mysql_real_connect(&mysql, HOST, USER, PASS, NULL, 0, (char *)NULL, 0))
    {
    printf("%s\n", mysql_error(&mysql));
    exit(1);
    }

    /* db를 선택 */
    if( mysql_select_db(&mysql, DB_NAME)){
    printf("%s\n", mysql_error(&mysql));
    exit(1);
    }

    num = atoi(argv[2]);

    for(i=0;i<num;i++)
    {
    sprintf(query, "insert into %s (userId, MailTo) values(\'ius[%d]\',\'%s\')", argv[1], i, argv[3]);

    res = mysql_query(&mysql, query);

    if (!res) {
    // printf("Inserted %lu rows\n", (unsigned long)mysql_affected_rows(&mysql));
    } else {
    fprintf(stderr, "Insert error %d: %s\n", mysql_errno(&mysql), mysql_error(&mysql));
    }
    }


    mysql_close(&mysql);
    (void)time(&clock2);
    printf("%d개의 자료를 성공적으로 삽입하였습니다.\n 수행 시간은 %ld 초 입니다\n", atoi(argv[2]), (long)clock2 - (long)clock1);
    return 0;
    }

    'MySQL' 카테고리의 다른 글

    MySQL 과 C 연동법  (0) 2006.11.20
    Calling MySQL from C  (0) 2006.11.20
    C 와 MySQL 의 연동  (0) 2006.11.20
    MySQL C-API Example  (0) 2006.11.20
    MySQL C API 로 unicode 데이터 insert 하기  (0) 2006.11.19
    , .