{{{ =========== 객체의 사용 =========== 일단 객체에 대한 개념이 있다는 전제하에 시작하겠습니다... 만일 객체에 대한 개념이 없으시다면 다른 웹문서나 서적을 참고하시기 바랍니다.. 오라클은 객체-관계형 데이타베이스 관리 시스템입니다.. 즉, 객체와 관계형 모델을 모두 지원해서 사용한다는 뜻입니다.. 물론 기준은 관계형 모델입니다... 객체를 관계형 모델에서 사용하는 것처럼 사용합니다... 즉, 객체지향의 중심개념인 캡슐화, 상속성, 다형성을 제공한다는 것입니다.. 객체형으로 선언하면 그 객체는 메소드와, 속성을 가질 수 있습니다.. 오브젝트 뷰라는 것도 있는데...이것은 오라클 관리 부분에서 다룹니다..그쪽을 참고하시구여.. 개념만 이야기 하자면 테이블에서 뷰를 만들고 이를 객체형으로 만든다는 것입니다.. 일단 객체를 정의하는 것부터 살펴보겠습니다.. 다시한번 말씀드리지만 이 부분은 객체에 대한 개념이 없으시다면 읽어도 무슨 소리인지 모를겁니다.. 위에서 말한것 처럼 객체의 개념을 익히시고 이 문서를 보시면 좋겠습니다.. C++이나 다른 객체지향형의 언어나 툴을 다루셨다면 이제까지 데이타베이스를 하면서 느끼지 못한 즐거움을 느끼실 겁니다..물론 객체형 데이타베이스를 하신분은 빼구여...헐헐~ 바로 실습에 들어가지여..언급한데로 PL/SQL의 예제는 (주)사이버출판사의 PL/SQL임돠... 문법은 메뉴얼을 참고하시구여... 쩝...맨날 메뉴얼 참고하라는데..메뉴얼이 있어야 어디서 보지...라구 외치시는 분덜은 제 자료실을 찾아보세요.. 제가 주로 참고하는 문서라고 있습니다.. 자..그러면 객체-관계형 DBMS인 오라클이 왜 객체-관계형이라고 하는지 실제로 해보면서 살펴봅시다.. 책에는 처음에 하기엔 너무 길고 어려운 예들이 많슴다...헐헐~ 이것은 나중에 하구여...제가 만들어서 해보겠슴다.. 객체에 대한 개념이 있다는 가정하에 밑에 것을 해보시게 된다면 금방 이해가 될 것이라 확신함돠.. 혹시나 객체에 대한 개념이 없으신 분덜이 아래 예를 해보신다면 객체가 먼지를 알지도 모르겠슴다.. SQL> create type test_object as object( 2 id varchar(4), 3 name varchar(10)); 4 / 유형이 생성되었습니다. SQL> create table test_object_table of test_object; -------------> 객체를 테이블화 했슴다... 테이블이 생성되었습니다. SQL> insert into test_object_table 2 values (test_object('1111', 'scott')); ---------------> 관계형 처럼 입력이 되는 것이 보입니다.. 1 개의 행이 만들어졌습니다. SQL> insert into test_object_table 2 values (test_object('2222', 'yasi')); 1 개의 행이 만들어졌습니다. SQL> select * from test_object_table; --------------> 객체타입을 사용해서 만든 테이블이 관계형에서와 똑같이 조회됩니다.. 이것이 바로 오라클을 객체-관계형 DBMS 라고 부르는 이유임돠.. ID NAME ---- ---------- 1111 scott 2222 yasi SQL> create table test_object_table2 2 ( id_name test_object, --------------> test_object는 앞에서 생성한 객체타입입니다...재사용성을 보여주고 있습니다.. 3 group_id varchar2(10)); 테이블이 생성되었습니다. SQL> select * from test_object_table2; 선택된 레코드가 없습니다. SQL> insert into test_object_table2 2 values (test_object('1111', 'system'), 'sysoper'); 1 개의 행이 만들어졌습니다. SQL> insert into test_object_table2 2 values (test_object('2222', 'yasi'), 'users'); 1 개의 행이 만들어졌습니다. SQL> select * from test_object_table2; ID_NAME(ID, NAME) GROUP_ID ---------------------------------------- ---------- TEST_OBJECT('1111', 'system') sysoper TEST_OBJECT('2222', 'yasi') users SQL> select t.id_name.id as id, -----------> 객체지향 언어에서 사용하는 점(.) 표시법으로 조회하고 있씀다... 2 t.id_name.name as name, 재밌슴다...^^ 3 t.group_id as group_id 4 from test_object_table2 t; ID NAME GROUP_ID ---- ---------- ---------- 1111 system sysoper 2222 yasi users SQL> create or replace type test_object2 as object( 2 id_name test_object, ----------> 앞에서 생성한 객체의 특성을 그대로 사용해서 또 다른 객체를 생성함돠.... 3 address varchar2(40)); 4 / 유형이 생성되었습니다. 헐~ 상당히 재밌씀다...저는 이것을 익히면서 너무나도 재미를 느꼈었슴다... 이것을 보시는 분덜도 그러리라 생각합니다...헐헐~ 이제 감을 잡으셨다고 생각하고 복잡한 예제를 보겠슴다.. SQL> CREATE OR REPLACE TYPE address AS OBJECT ( 2 street_1 VARCHAR2(40), 3 street_2 VARCHAR2(40), 4 city VARCHAR2(40), 5 state_abbr VARCHAR2(2), 6 zip_code VARCHAR2(5), 7 phone_number VARCHAR2(10), 8 MEMBER PROCEDURE ChangeAddress ( -------------------> 메소드까정 생성 9 st_1 IN VARCHAR2, st_2 IN VARCHAR2, cty IN VARCHAR2, 10 state IN VARCHAR2, zip IN VARCHAR2), 11 MEMBER FUNCTION getStreet (line_no IN number) RETURN VARCHAR2, 12 MEMBER FUNCTION getCity RETURN VARCHAR2, 13 MEMBER FUNCTION getStateAbbr RETURN VARCHAR2, 14 MEMBER FUNCTION getPostalCode RETURN VARCHAR2, 15 MEMBER FUNCTION getPhone RETURN VARCHAR2, 16 MEMBER PROCEDURE setPhone (newPhone IN VARCHAR2) 17 ); 18 / 유형이 생성되었습니다. address라는 객체타입을 생성했습니다... 프로시저와 함수를 선언했지여...프로시저는 리턴값이 없는 것을 야그하고, 함수는 리턴값이 있는 것을 말합니다... 이러한 메소드를 생성하는 이유는 생성한 객체타입에 대한 조작을 하기 위한 것이지여... 패키지 생성하는 것처럼 몸체도 생성해 주어야 합니다... 컬럼 비스무리하게 선언한 것은 속성임돠...오라클의 객체타입은 속성을 1000개까정 가질수 있슴다.. 그럼 몸체를 생성해 보겠슴다.. SQL> CREATE OR REPLACE TYPE address AS OBJECT ( 2 street_1 VARCHAR2(40), 3 street_2 VARCHAR2(40), 4 city VARCHAR2(40), 5 state_abbr VARCHAR2(2), 6 zip_code VARCHAR2(5), 7 phone_number VARCHAR2(10), 8 MEMBER PROCEDURE ChangeAddress ( 9 st_1 IN VARCHAR2, st_2 IN VARCHAR2, cty IN VARCHAR2, 10 state IN VARCHAR2, zip IN VARCHAR2), 11 MEMBER FUNCTION getStreet (line_no IN number) RETURN VARCHAR2, 12 MEMBER FUNCTION getCity RETURN VARCHAR2, 13 MEMBER FUNCTION getStateAbbr RETURN VARCHAR2, 14 MEMBER FUNCTION getPostalCode RETURN VARCHAR2, 15 MEMBER FUNCTION getPhone RETURN VARCHAR2, 16 MEMBER PROCEDURE setPhone (newPhone IN VARCHAR2) 17 ); 18 / 유형이 생성되었습니다. SQL> CREATE OR REPLACE TYPE BODY address AS 2 MEMBER PROCEDURE ChangeAddress ( 3 st_1 IN VARCHAR2, st_2 IN VARCHAR2, cty IN VARCHAR2, 4 state IN VARCHAR2, zip IN VARCHAR2) IS 5 BEGIN 6 IF (st_1 IS NULL) OR (cty IS NULL) OR 7 (state IS NULL) OR (zip IS NULL) 8 OR (upper(state) NOT IN ('AK','AL','AR','AZ','CA','CO', 9 'CT','DC','DE','FL','GA','HI', 10 'IA','ID','IL','IN','KS','KY', 11 'LA','MA','MD','ME','MI','MN', 12 'MO','MS','MT','NC','ND','NE', 13 'NH','NJ','NM','NV','NY','OH', 14 'OK','OR','PA','RI','SC','SD', 15 'TN','TX','UT','VA','VT','WA', 16 'WI','WV','WY')) 17 OR (zip <> ltrim(to_char(to_number(zip),'09999'))) THEN 18 RAISE_application_error(-20001,'The new Address is invalid.'); 19 ELSE 20 street_1 := st_1; 21 street_2 := st_2; 22 city := cty; 23 state_abbr := upper(state); 24 zip_code := zip; 25 END IF; 26 END; 27 28 MEMBER FUNCTION getStreet (line_no IN number) 29 RETURN VARCHAR2 IS 30 BEGIN 31 IF line_no = 1 THEN 32 RETURN street_1; 33 ELSIF line_no = 2 THEN 34 RETURN street_2; 35 ELSE 36 RETURN ' '; --send back a blank. 37 END IF; 38 END; 39 40 MEMBER FUNCTION getCity RETURN VARCHAR2 IS 41 BEGIN 42 RETURN city; 43 END; 44 45 MEMBER FUNCTION getStateAbbr RETURN VARCHAR2 IS 46 BEGIN 47 RETURN state_abbr; 48 END; 49 50 MEMBER FUNCTION getPostalCode RETURN VARCHAR2 IS 51 BEGIN 52 RETURN zip_code; 53 END; 54 55 MEMBER FUNCTION getPhone RETURN VARCHAR2 IS 56 BEGIN 57 RETURN phone_number; 58 END; 59 60 MEMBER PROCEDURE setPhone (newPhone IN VARCHAR2) IS 61 BEGIN 62 phone_number := newPhone; 63 END; 64 END; 65 / 유형 본문이 생성되었습니다. 헐헐~ 상당히 길지만....패턴은 비슷함돠... MEMBER PROCEDURE ChangeAddress 는 속성에 대한 변경을 하려고 만든 프로시저입니다... 속성 각각에 입력되거나 갱신할때 데이타의 무결성을 유지하기 위한 제어문이 들어갔슴다.. 각각의 멤버 함수는 값을 리턴하기 위해서 생성된 것들입니다... 오라클의 객체타입에는 생성자 메소드라는 것이 내장되어 있습니다... 이것은 그 객체형의 인스턴스를 생성하는데 사용됩니다.. 그 생성자 메소드는 다음과 같은 식이지여.. FUNCTION address(street_1 in varchar2, street_2 in varchar2, city in varchar2, state_abbr,.............) returns address 이런 생성자 메소드는 항상 같은 형의 객체를 반환합니다... 생성자 함수의 사용은 다음과 같이 하지여.. address_variable := address('101 Oak', '', 'Detroit', 'MI', '48223', '3135358886'); 함수의 몸체에서 다음을 살펴봅시다.. MEMBER FUNCTION getPhone RETURN VARCHAR2 IS BEGIN RETURN phone_number; END; 속성을 반환하는데 사용되는 메소드입니다...이 메소드를 Accessor Method라 합니다... 일반적으로 get이란 접두어를 사용합니다.. 그 밑에 있는 setPhone은 mutator Method라는 것입니다...코드상에서 보는 것과 같이 속성을 직접 참조하지 않습니다.. 즉, 속성을 직접 건더리지 않고 간접적으로 건더리는 것입니다... MEMBER PROCEDURE setPhone (newPhone IN VARCHAR2) IS BEGIN phone_number := newPhone; END; 자...그럼 이러한 메소드를 사용해서 객체타입의 인스턴스를 생성하고, 조회해 보겠슴다.. SQL> set serveroutput on SQL> SQL> --A PL/SQL block demonstrating the SQL> --use of the address object. SQL> DECLARE 2 address_1 address; 3 address_2 address; 4 address_3 address; 5 BEGIN 6 --Instantiate a new address object named address_1, 7 --and assign a copy of it to address_2. 8 address_1 := address ('2700 Peerless Road','Apt 1', -------------> address는 생성자 함수지여? address_1이 새로운 인스턴스가 됩니다.. 9 'Cleveland','TN','37312','4235551212'); 10 address_2 := address_1; 11 12 --Change address #1 13 address_1.ChangeAddress ('2800 Peermore Road','Apt 99', 14 'Detroit','MI','48823'); --------------> ChangeAddress 프로시저를 사용해서 인스턴스를 갱신함돠.. 15 16 --Instantiate a second object. 17 address_3 := address ('2700 Eaton Rapids Road','Lot 98', 18 'Lansing','MI','48911','5173943551'); 19 20 --Now print out the attributes from each object. 21 dbms_output.put_line('Attributes for address_1:'); -------------> 여기부터는 생성한 인스턴스를 이쁘게 보여주기 위한 짓임돠.. 22 dbms_output.put_line(address_1.getStreet(1)); -------------> 객체형으로 생성해서 엑서스 메소드를 사용합니다..객체의 사용처럼 점표시법으로... 23 dbms_output.put_line(address_1.getStreet(2)); 24 dbms_output.put_line(address_1.getCity 25 || ' ' || address_1.getStateAbbr 26 || ' ' || address_1.getPostalCode); 27 dbms_output.put_line(address_1.getPhone); 28 29 dbms_output.put_line('-------------------------'); 30 dbms_output.put_line('Attributes for address_2:'); 31 dbms_output.put_line(address_2.getStreet(1)); 32 dbms_output.put_line(address_2.getStreet(2)); 33 dbms_output.put_line(address_2.getCity 34 || ' ' || address_2.getStateAbbr 35 || ' ' || address_2.getPostalCode); 36 dbms_output.put_line(address_2.getPhone); 37 38 dbms_output.put_line('-------------------------'); 39 dbms_output.put_line('Attributes for address_3:'); 40 dbms_output.put_line(address_3.street_1); 41 dbms_output.put_line(address_3.street_2); 42 dbms_output.put_line(address_3.city 43 || ' ' || address_3.state_abbr 44 || ' ' || address_3.zip_code); 45 dbms_output.put_line(address_3.phone_number); 46 END; 47 / Attributes for address_1: 2800 Peermore Road Apt 99 Detroit MI 48823 4235551212 ------------------------- Attributes for address_2: 2700 Peerless Road Apt 1 Cleveland TN 37312 4235551212 ------------------------- Attributes for address_3: 2700 Eaton Rapids Road Lot 98 Lansing MI 48911 5173943551 PL/SQL 처리가 정상적으로 완료되었습니다. 노가다입니다...헐헐~ 이상스럽게 이러한 예제는 비효율적이라고 생각합니다... 웬지 그런 느낌이 드네여..헐헐~ 암튼... 여기까지 했으면 감이 잡혔지여?? 다른 것을 살펴보구 갱신하는 짓을 해봅시다... SQL> CREATE TABLE employee 2 (emp_id INTEGER, 3 emp_name VARCHAR2(32), 4 supervised_by INTEGER, 5 pay_rate NUMBER(9,2), 6 pay_type CHAR); 테이블이 생성되었습니다. SQL> alter table employee 2 add (home_address address); ------------------> 객체형으로 정의된 컬럼을 추가합니다. 테이블이 변경되었습니다. SQL> INSERT INTO employee 2 (emp_id, emp_name,pay_rate,pay_type,home_address) 3 VALUES (597,'Matthew Higgenbottom',120000,'S', 4 address('101 Maple','','Mio','MI','48640','5173943551')); --------> 데이타 삽입 1 개의 행이 만들어졌습니다. SQL> SQL> COMMIT; 커밋이 완료되었습니다. SQL> SQL> DECLARE 2 emp_home_address address; ---------------------> 객체형으로 변수 선언 3 BEGIN 4 emp_home_address := address('911 Pearl','Apt 2','Lewiston', 5 'MI','48645','5173363366'); 6 INSERT INTO employee 7 (emp_id, emp_name,pay_rate,pay_type,home_address) 8 VALUES (598, 'Raymond Gennick',55,'H',emp_home_address); 9 COMMIT; 10 END; 11 / PL/SQL 처리가 정상적으로 완료되었습니다. SQL> SELECT emp_id, emp_name, home_address 2 FROM employee 3 WHERE home_address IS NOT null; EMP_ID EMP_NAME HOME_ADDRESS(STREET_1, STREET_2, CITY, STATE_ABBR, ZIP_CODE, PHONE_NUMBER) ---------- -------------------------------- -------------------------------------------------------------------------------- 597 Matthew Higgenbottom ADDRESS('101 Maple', NULL, 'Mio', 'MI', '48640', '5173943551') 598 Raymond Gennick ADDRESS('911 Pearl', 'Apt 2', 'Lewiston', 'MI', '48645', '5173363366') 설명을 안해도 될꺼 같습니다... 이제 갱신하는 것을 해보겠습니다...기본적으로 PL/SQL 어케돌아가는지 아신다면 쉽습니다... SQL> DECLARE 2 emp_addr address; 3 BEGIN 4 --Retrieve the object from the table 5 SELECT home_address INTO emp_addr 6 FROM employee 7 WHERE emp_id = 597; 8 9 --Use a mutator method to change the phone number. 10 emp_addr.setPhone('3139830301'); --------------> 뮤테이터 메소드를 사용해서 갱신함돠.. 11 12 UPDATE employee 13 SET home_address = emp_addr 14 WHERE emp_id = 597; 15 16 COMMIT; 17 END; 18 / PL/SQL 처리가 정상적으로 완료되었습니다. SQL> SELECT emp_id, emp_name, e.home_address.phone_number home_phone 2 FROM employee e 3 WHERE emp_id = 597; EMP_ID EMP_NAME HOME_PHONE ---------- -------------------------------- ---------- 597 Matthew Higgenbottom 3139830301 SQL> UPDATE employee e 2 SET e.home_address = address(e.home_address.street_1, 3 e.home_address.street_2, e.home_address.city, 4 e.home_address.state_abbr, e.home_address.zip_code, 5 '5173433333') 6 WHERE emp_id = 598; 1 행이 갱신되었습니다. SQL> COMMIT; 커밋이 완료되었습니다. 마지막에서 살펴본 갱신문도....처음에 해본것들과 비슷합니다...점표시법을 사용해서 잘 구분해주고... 각각을 조회, 갱신, 입력, 삭제할 수 있습니다... 그러면 오라클은 어떻게 객체를 사용하는데 각각을 구분하는 방법을 생각해봅시다... 구분하는 방법은 각 테이블의 컬럼으로 정의된 객체의 각 속성에 일치합니다... 따라서 테이블의 각 행은 객체의 한 인스턴스를 저장하는데 사용됩니다... 이렇게 구분하는 방법말구...오라클은 Object idenfifier란 오라클의 생성하는 값으로 구분을 합니다.. 이 값은 각각 생성한 객체를 데이타베이스 전체에서 고유하게 구별하는 것 입니다... 다음은 객체형 테이블을 만드는 예를 살펴보겠슴다.. SQL> CREATE OR REPLACE TYPE building AS OBJECT ( 2 BldgName VARCHAR2(40), 3 BldgAddress address, 4 BldgMgr INTEGER, 5 MEMBER PROCEDURE ChangeMgr (NewMgr IN INTEGER), 6 ORDER MEMBER FUNCTION Compare (OtherBuilding IN building) ---------> ORDER 형 멤버 함수를 사용 7 RETURN INTEGER 8 ); 9 / 유형이 생성되었습니다. 여기서 봐야 될것은 ORDER 입니다... 이제까지 했던 다른 것들하고 먼가가 틀립니다... ORDER 함수는 두 객체를 비교하는 코드를 작성할 수 있게 해줍니다.. 두 객체가 같은지 아니면 어떤 것이 더 큰지 또는 작은지 가리키는 값을 반환합니다.. 나중에 더 살펴보구여...일단 이런것이라는 것만 알고 계시면 되리라 생각합니다.. SQL> CREATE OR REPLACE TYPE BODY building AS 2 MEMBER PROCEDURE ChangeMgr(NewMgr IN INTEGER) IS 3 BEGIN 4 BldgMgr := NewMgr; 5 END; 6 7 ORDER MEMBER FUNCTION Compare (OtherBuilding IN building) 8 RETURN INTEGER IS 9 BldgName1 VARCHAR2(40); 10 BldgName2 building.BldgName%TYPE; ------------> '변수이름 테이블이름.컬럼이름%TYPE' 의 형식을 같습니다.. 11 BEGIN 12 --Grab the two building names for comparison. 13 --Make sure that we don't get messed up by leading/trailing 14 --spaces or by case. 15 BldgName1 := upper(ltrim(rtrim(BldgName))); ---------------> 앞뒤 공백을 모두 없애고 대문자로 치환해서 BldgName1에 넣구 있슴다.. 16 BldgName2 := upper(ltrim(rtrim(OtherBuilding.BldgName))); 17 18 --Return the appropriate value to indicate the order of 19 --this object vs OtherBuilding. 20 IF BldgName1 = BldgName2 THEN -----------------> 두 값의 비교를 위한 제어문입니다.. 21 RETURN 0; 22 ELSIF BldgName1 < BldgName2 THEN 23 RETURN -1; 24 ELSE 25 RETURN 1; 26 END IF; 27 END; 28 END; 29 / 유형 본문이 생성되었습니다. SQL> CREATE TABLE buildings OF building; ---------> 객체형 테이블 생성 테이블이 생성되었습니다. SQL> INSERT INTO buildings 2 values (building('Victor Building', 3 address('203 Washington Square',' ','Lansing', 4 'MI','48823',' '), 5 597)); 1 개의 행이 만들어졌습니다. SQL> SQL> INSERT INTO buildings 2 values (building('East Storage Shed', 3 address('1400 Abbott Rd','','Lansing','MI','48823',''), 4 598)); 1 개의 행이 만들어졌습니다. SQL> INSERT INTO buildings 2 values (building('Headquarters Building', 3 address('150 West Jefferson','','Detroit','MI','48226',''), 4 599)); 1 개의 행이 만들어졌습니다. SQL> SQL> SELECT * from buildings; BLDGNAME BLDGADDRESS(STREET_1, STREET_2, CITY, STATE_ABBR, ZIP_CODE, PHONE_NUMBER) BLDGMGR ---------------------------------------- ------------------------------------------------------------------------- ---------- Victor Building ADDRESS('203 Washington Square', ' ', 'Lansing', 'MI', '48823', ' ') 597 East Storage Shed ADDRESS('1400 Abbott Rd', NULL, 'Lansing', 'MI', '48823', NULL) 598 Headquarters Building ADDRESS('150 West Jefferson', NULL, 'Detroit', 'MI', '48226', NULL) 599 SQL> COMMIT; 커밋이 완료되었습니다. 다음은 객체형 테이블에 대한 검색을 하는 또다른 예를 보겠습니다... 객체형 테이블을 검색하는 또다른 방법은 VALUE라는 연산자를 사용하는 것입니다.. SQL> select value(e) from buildings e; VALUE(E)(BLDGNAME, BLDGADDRESS(STREET_1, STREET_2, CITY, STATE_ABBR, ZIP_CODE, PHONE_NUMBER), BLDGMG ---------------------------------------------------------------------------------------------------- BUILDING('Victor Building', ADDRESS('203 Washington Square', ' ', 'Lansing', 'MI', '48823', ' '), 59 BUILDING('East Storage Shed', ADDRESS('1400 Abbott Rd', NULL, 'Lansing', 'MI', '48823', NULL), 598) BUILDING('Headquarters Building', ADDRESS('150 West Jefferson', NULL, 'Detroit', 'MI', '48226', NULL SQL> desc building 이름 널? 유형 --------------------------------------------------------------------------------------------------- BLDGNAME VARCHAR2(40) BLDGADDRESS ADDRESS BLDGMGR NUMBER(38) METHOD ------ MEMBER PROCEDURE CHANGEMGR 인수명 유형 기본 내부/외부? ------------------------------ ----------------------- --------- -------- NEWMGR NUMBER IN METHOD ------ ORDER MEMBER FUNCTION COMPARE RETURNS NUMBER 인수명 유형 기본 내부/외부? ------------------------------ ----------------------- --------- -------- OTHERBUILDING BUILDING IN SQL> 다음은 이러한 객체형의 문제점을 살펴보구 오라클이 이 문제점을 해결하는 방안을 살펴보겠습니다... 예를 들면, 어떤 빌딩에 1000명의 사원이 있다면, 각 사원대 해새 하나씩 1000개의 독립된 building 객체가 있게 됩니다.. 결국 너무 많은 정보를 갖게 되는 것이죠... 이런한 것을 해결하기 위해 오라클은 오브젝트에 대한 참조만 저장합니다..참조의 생성은 REF를 사용합니다.. 즉, 객체를 사용하는 것이 아니라 참조만 한다는 뜻입니다.. 오라클 관리 부분에도 언급되었던 것이죠.. 참조를 생성해 봅시다... SQL> ALTER TABLE employee 2 ADD (emp_bldg REF building); 테이블이 변경되었습니다. 예에서 보면 building 객체를 사용하는 것이 아니라 참조합니다...즉, 오라클은 객체 식별자를 처리하는데 REF와 DEREF 연산자를 사용한다는 것입니다.. REF 연산자는 오브젝트에 대한 오브젝트 식별자를 반환하는 SQL문에서 사용되고, DEREF 연산자는 오브젝트 식별자에 의해 참조되는 실제 오브젝트를 검색하는 SQL문에서 사용합니다. REF연산자와 DEREF 연산자를 사용하는 예를 연속으로 보겠씁니다.. SQL> CREATE OR REPLACE PROCEDURE AssignEmpToBldg ( 2 EmpNumIn IN employee.emp_id%TYPE, 3 BldgNameIn IN buildings.BldgName%TYPE 4 ) AS 5 BEGIN 6 UPDATE employee 7 SET emp_bldg = (SELECT REF(b) -------------> REF연산자 사용, buildings 테이블에서 사용한 객체에 대한 참조만 한다. 8 FROM buildings B 9 WHERE BldgName = BldgNameIn) 10 WHERE emp_id = EmpNumIn; 11 12 --Raise an error if either the employee number or 13 --building name is invalid. 14 IF SQL%NOTFOUND THEN 15 RAISE_application_error(-20000,'Employee ' || EmpNumIn 16 || ' could not be assigned to building ' 17 || BldgNameIn); 18 END IF; 19 END; 20 / 프로시저가 생성되었습니다. SQL> SQL> BEGIN 2 AssignEmpToBldg (598,'Victor Building'); 3 AssignEmpToBldg (597,'East Storage Shed'); 4 END; 5 / PL/SQL 처리가 정상적으로 완료되었습니다. SQL> CREATE OR REPLACE FUNCTION GetEmpBldgName ( 2 EmpNumIn IN employee.emp_id%TYPE 3 ) RETURN VARCHAR2 AS 4 TheBldg building; 5 BEGIN 6 --Select the building object reference from this employee's record. 7 SELECT DEREF(emp_bldg) INTO TheBldg -------------------> 실제 객체에 대한 검색을 한다.즉, 참조를 해제한다. 8 FROM employee 9 WHERE emp_id = EmpNumIn; 10 11 IF TheBldg IS NULL THEN 12 RETURN 'No Building Assigned'; 13 ELSE 14 RETURN TheBldg.BldgName; 15 END IF; 16 END; 17 / 함수가 생성되었습니다. SQL> SQL> BEGIN 2 dbms_output.put_line(GetEmpBldgName(598)); 3 dbms_output.put_line(GetEmpBldgName(597)); 4 END; 5 / Victor Building East Storage Shed PL/SQL 처리가 정상적으로 완료되었습니다. 주의깊게 볼것은 어떤 것이 참조를 하는지 알아서 참조해제를 하는 것이냐? 입니다.. DEREF 연산자에 의해서 사용되는 오브젝트 참조에는 오라클이 객체를 찾는데 필요한 모든 정보가 들어 있습니다..그래서 관계형 테이블에서 사용되는 조인문에서와 같이 엑세스할 테이블을 지정하지 않아도 되는 것입니다.. 참고로 메뉴얼의 문법을 보면 SELF 파라미터가 있는데...이것은 메소드를 작성시 기본값입니다. 호출되는 객체의 속성을 참조하는데 사용됩니다. 이제 객체타입에 대한 기나긴 장정의 마지막인 객체 비교하는 것을 해보구....제약사항을 알아 보겠습니다.. 객체 비교에는 두가지 메소드를 지원합니다... 그 두가지는 앞에서 잠시 살펴본 ORDER와 MAP 메소드입니다.. 먼저 ORDER에 대해서 살펴보게습니다.. 앞에서 살펴본 예제에서 다음과 같은 구문이 있었습니다.. ORDER MEMBER FUNCTION Compare (OtherBuilding IN building) RETURN INTEGER ORDER 예약어는 Compare 함수가 한 building 객체를 다른 building 객체와 비교할 때 호출되도록 특별히 작성된 함수라는 것을 말해주는 것입니다.. 함수가 취하는 인수는 오브젝트와 같은 형이어야 합니다.. ORDER함수는 SELF 파라미터에서 알아본 것처럼 비교하여 다음과 같은 값을 반환합니다.. 반환값 의미 ------------ ------------------ -1 SELF가 인수보다 작다. 0 SELF가 인수와 같다. 1 SELF가 인수보다 크다. 다음은 예입니다.. SQL> set serveroutput on SQL> SQL> --A demonstration of the ORDER function. SQL> DECLARE 2 bldg_a building; --will be less than bldg_b 3 bldg_b building; 4 bldg_b2 building; 5 bldg_c building; 6 BEGIN 7 --First, create four building objects. 8 bldg_a := building('A Building',null,null); 9 bldg_b := building('Another Building',null,null); 10 bldg_b2 := building('Another Building',null,null); 11 bldg_c := building('Cosmotology Research Lab',null,null); 12 13 --Now compare the building objects and display the results; 14 IF bldg_a < bldg_b THEN 15 dbms_output.put_line('bldg_a < bldg_b'); 16 END IF; 17 18 --These two have the same name, so should be equal. 19 IF bldg_b = bldg_b2 THEN 20 dbms_output.put_line('bldg_b = bldg_b2'); 21 END IF; 22 23 IF bldg_c > bldg_b2 THEN 24 dbms_output.put_line('bldg_c > bldg_b2'); 25 END IF; 26 END; 27 / bldg_a < bldg_b bldg_b = bldg_b2 bldg_c > bldg_b2 PL/SQL 처리가 정상적으로 완료되었습니다. MAP 메소드는 ORDER 함수대신 사용할 수 있는 다른 방법입니다.. MAP 함수는 객체의 하나 또는 그 이상의 속성에 따라 하나의 값을 계산합니다..그리고 그 값을 한 객체와 다른 객체(같은 객체형)를 비교하는데 사용합니다... MAP함수의 결과는 다음 데이타형중 하나이어야 합니다.. - NUMBER - DATE - VARCHAR2 마지막으로 오라클의 객체타입에 대한 제약사항을 알보구 마치겠씁니다.. - 상속성을 지원하지 않는다. --------------> 책에 나온 내용인데...이상함돠..제가 알기론 상속성을 지원하는데 말이죠..아무래도 완벽하지는 않은듯.. - PRIVATE 속성을 지원하지 않는다. - 사용자 정의 생성자를 지원하지 않는다. - 객체형은 데이타베이스 수준에서 정의되어야 하며, PL/SQL 함수나 프로시저 내에서 정의할 수 없다. - 일부 데이타형은 속성으로 사용될 수 없다. - 객체의 속성의 개수를 최대 1000개 이상 사용할 없다. }}}