posted by 구름너머 2004. 10. 15. 10:10

오라클 데이터베이스 scott유저의 emp테이블을 보면 empno와 mgr컬럼이 있습니다.


mgr 컬럼의 데이터는 해당 사원의 관리자의 empno를 의미 합니다.


예를 들어서 아래의 데이터를 보면은..


EMPNO ENAME SAL MGR
------ --------- ------- ----------
7369 SMITH 800 7902
7902 FORD 3000 7566


empno 7369사원의 관리자는 7902의 empno를 가진 사원이며
empno 7902사원의 관리자는 7566의 empno를 가진 사원입니다.


이런 상위 계층과 하위계층의 관계를 오라클에서는 START WITHCONNECT BY를 이용해서
쉽게 가져올 수 있습니다.

상품의 카테고리(대분류,중분류,소분류...)를 조회 할때 START WITH와 CONNECT BY를 이용하면
트리 구조로 편리하게 조회 할 수 있습니다.


게시판에서의 일반글과 답변글 과의 관계에서도 사용 할 수 있습니다.



START WITH와 CONNECT BY를 이용해 데이터를 계층적인 순서로 조회할 수 있습니다.


START WITH

- 계층 질의의 루트(부모행)로 사용될 행을 지정 합니다..
- 서브쿼리를 사용할 수도 있습니다.


CONNECT BY

- 이 절을 이용하여 계층 질의에서 상위계층(부모행)과 하위계층(자식행)의 관계를 규정 합니다.
- 보통 PRIOR 연산자를 많이 사용 합니다..
- 서브쿼리를 사용할 수 없습니다..



CONNECT BY의 실행순서는 다음과 같습니다.

- 첫째 START WITH절
- 둘째 CONNECT BY 절
- 세째 WHERE 절 순서로 풀리게 되어있습니다.


-- 테스트를 위해서 scott유저로 접속을 합니다.
SQLPLUS scott/tiger


예제1)상위계층과 하위 계층 관계의 순서대로 쿼리해 옴


-- LEVEL 예약어를 사용하여 depth를 표현 할 수 있습니다.
-- 직업이 PRESIDENT을 기준으로 계층 구조로 조회합니다.

SQL>SELECT LEVEL,empno,ename, mgr
FROM emp
START WITH job = 'PRESIDENT' -- 직업이 PRESIDENT를 기준으로
CONNECT BY PRIOR empno = mgr; -- 사원(empno)과 관리자(mgr)의 관계를 계층 구조로 조회

LEVEL EMPNO ENAME MGR
--------- ---------- -------------------- ----------
1 7839 KING
2 7566 JONES 7839
3 7788 SCOTT 7566
4 7876 ADAMS 7788
3 7902 FORD 7566
4 7369 SMITH 7902
2 7698 BLAKE 7839
3 7499 ALLEN 7698
3 7521 WARD 7698
3 7654 MARTIN 7698
3 7844 TURNER 7698
3 7900 JAMES 7698
2 7782 CLARK 7839
3 7934 MILLER 7782


-- LEVEL컬럼은 depth를 나타냅니다.
-- JONES의 관리자는 KING을 나타냅니다.
-- SCOTT의 관리자는 JONES를 나타냅니다.
-- 예제와 같이 상/하의 계층 구조를 쉽게 조회 할 수 있습니다.




예제2) 사원성명을 계층 구조로 보여 줌


SQL>SET LINESIZE 100
SQL>SET PAGESIZE 100
SQL>COL ename FORMAT A20

-- 예제1의 결과를 가지고 LPAD함수를 이용해서 ename왼쪽에 공백을 추가 했습니다.
SQL>SELECT LPAD(' ', 4*(LEVEL-1)) || ename ename, empno, mgr, job
FROM emp
START WITH job='PRESIDENT'
CONNECT BY PRIOR empno=mgr;

ENAME EMPNO MGR JOB
-------------------- ---------- ---------- ---------
KING 7839 PRESIDENT
JONES 7566 7839 MANAGER
SCOTT 7788 7566 ANALYST
ADAMS 7876 7788 CLERK
FORD 7902 7566 ANALYST
SMITH 7369 7902 CLERK
BLAKE 7698 7839 MANAGER
ALLEN 7499 7698 SALESMAN
WARD 7521 7698 SALESMAN
MARTIN 7654 7698 SALESMAN
TURNER 7844 7698 SALESMAN
JAMES 7900 7698 CLERK
CLARK 7782 7839 MANAGER
MILLER 7934 7782 CLERK


예제3) 레벨이 2까지만 쿼리해서 가져오는 예제

SQL>SELECT LPAD(' ', 4*(LEVEL-1)) || ename ename, empno, mgr, job
FROM emp
START WITH job='PRESIDENT'
CONNECT BY PRIOR empno=mgr
AND LEVEL <=2 ;

ENAME EMPNO MGR JOB
-------------------- ---------- ---------- ---------
KING 7839 PRESIDENT
JONES 7566 7839 MANAGER
BLAKE 7698 7839 MANAGER
CLARK 7782 7839 MANAGER



예제4) 각 label별로 급여의 합과 인원수를 구하는 예제

SQL> SELECT LEVEL, SUM(sal) total,COUNT(empno) cnt
FROM emp
START WITH job='PRESIDENT'
CONNECT BY PRIOR empno=mgr
GROUP BY LEVEL
ORDER BY LEVEL;

LEVEL TOTAL CNT
---------- ---------- ----------
1 5000 1
2 8275 3
3 13850 8
4 1900 2




데이터가 많아질 경우....

-
첫째로 풀리는 START WITH job='PRESIDENT' job 컬럼에 index가 생성되어 있지 않는다면
속도를 보장할 수 없습니다.

- 그리고 둘째로 풀리는 CONNECT BY PRIOR empno = mgr 역시 PRIOR 쪽의 컬럼값이 상수가
되기 때문에 MGR컬럼에 index를 생성하여야 CONNECT BY의 속도를 보장할 수 있습니다.

- 계층구조를 CONNECT BY, START WITH로 풀면 부분범위 처리가 불가능하고 Desc으로
표현하기가 어렵 습니다.


참고..

http://dblab.changwon.ac.kr/oracle/sqltest/hierarchical.html/
http://www.en-core.com/

posted by 구름너머 2004. 10. 15. 09:59

1. EXECUTE IMMEDIATE를 이용한 Dynamic SQL


Oracle 8i에서의 Dynamic SQL은 두가지 방법이 있습니다.

첫번째 방법은 "EXECUTE IMMEDIATE" 절을 사용하여 embedded dynamic sql을 구현하는
방법이고,

두번째 방법은 선언되어지는 것 대신에 실행시에 문장을 보내는 ref cursor의 확장된 개념으로
query를 위해 사용되어지는 방법 입니다.


여기서는 EXECUTE IMMEDIATE를 이용한 Dynamic SQL에 대해서 알아보겠습니다.

[Syntax]

EXECUTE IMMEDIATE dynamic_sql_string
[INTO {define_var1 [, define_var2] ... | plsql_record }]
[USING [IN | OUT | IN OUT] bind_arg1 [,
[IN | OUT | IN OUT] bind_arg2] ...];



2. 간단하게 테이블을 생성하는 예제 입니다


첫번째 예제는 간단하게 테이블을 생성하는 예제 입니다.

==========================================================

CREATE OR REPLACE PROCEDURE dynamic_sql_01
IS

str varchar2(200);

BEGIN

str := 'CREATE TABLE total (total number)';
EXECUTE IMMEDIATE str;

END;

==========================================================

프로시저가 생성되었습니다.


-- 프로시저를 실행해서 테이블을 생성 합니다.
SQL> EXEC dynamic_sql_01;
PL/SQL 처리가 정상적으로 완료되었습니다.


-- 생성된 테이블을 확인해 봅니다.
SQL> DESC total;
이름 널? 유형
----------------------------------------- -------- -----------
TOTAL NUMBER



* 프로시저 생성시 "ORA-01031: 권한이 불충분합니다" 에러가 발생하면
system유저로 접속을 해서 EXECUTE IMMEDIATE를 실행하는 유저에게
CREATE ANY TABLE 권한을 부여 합니다.

SQL> CONN system/manager
SQL> GRANT create any table TO scott;



3. 테이블 생성 후 INSERT 예제


두번째 예제는 TABLE_ROWS라는 테이블을 생성하고, 다이나믹 하게 테이블명을 입력하면
테이블명과 테이블에 등록된 데이터수를 TABLE_ROWS에 INSERT하고 출력하는 예제 입니다.


===============================================================

CREATE OR REPLACE PROCEDURE dynamic_sql_02
(v_table_name IN VARCHAR2)
IS

v_str VARCHAR2(200);
v_cnt NUMBER;
v_temp VARCHAR2(50);

CURSOR cur_exists IS
SELECT TABLE_NAME
FROM USER_TABLES
WHERE table_name = 'TABLE_ROWS';

BEGIN

OPEN cur_exists
FETCH cur_exists INTO v_temp;


-- 테이블이 존재하면 테이블을 삭제 합니다.
IF cur_exists%FOUND THEN
v_str := 'DROP TABLE table_rows';
EXECUTE IMMEDIATE v_str;
END IF;

-- 테이블 생성
v_str := 'CREATE TABLE table_rows (total number, table_name varchar2(50))';
EXECUTE IMMEDIATE v_str;


-- 데이터 카운트 조회
v_str := 'SELECT COUNT(*) cnt FROM '||v_table_name ;
EXECUTE IMMEDIATE v_str INTO v_cnt ;


-- 데이터 insert
v_str := 'INSERT INTO table_rows VALUES ('||v_cnt||', :A1 )';
EXECUTE IMMEDIATE v_str USING v_table_name;


DBMS_OUTPUT.PUT_LINE(' 테이블 명 : '||v_table_name||' 데이터 수 : '||v_cnt);

CLOSE cur_exists;

END;
/
===============================================================

프로시저가 생성되었습니다.

SQL> SET SERVEROUTPUT ON:

-- emp 테이블명과 테이블의 데이터카운트를 INSERT합니다.
SQL> EXEC dynamic_sql_02('emp');
테이블 명 : emp 데이터 수 : 14

PL/SQL 처리가 정상적으로 완료되었습니다.


-- 정상적으로 처리되었는지 확인해 봅니다.
SQL> SELECT * FROM table_rows;

TOTAL TABLE_NAME
---------- --------------
14 emp


posted by 구름너머 2004. 10. 15. 09:55


◈ DB에 등록된 유저의 정보 조회

- dba_users 데이터 사전을 이용하시면 됩니다.


SQL>col username format a15
SQL>col default_tablespace format a15
SQL>col temperary_tablespace format a15
SQL>SELECT username, default_tablespace, temporary_tablespace, created
FROM dba_users

USERNAME DEFAULT_TABLESP TEMPORARY_TABLESPACE CREATED
--------------- --------------- ------------------------------ --------
SYS SYSTEM TEMP 01/03/25
SYSTEM TOOLS TEMP 01/03/25
OUTLN SYSTEM SYSTEM 01/03/25
DBSNMP SYSTEM SYSTEM 01/03/25
SCOTT SYSTEM SYSTEM 01/03/25
ADAMS SYSTEM SYSTEM 01/03/25
OEM OEM_REPOSITORY TEMP 01/10/11
JONES SYSTEM SYSTEM 01/03/25
CLARK SYSTEM SYSTEM 01/03/25
BLAKE SYSTEM SYSTEM 01/03/25
....

18개의 행이 선택되었습니다.


DEFAULT_TABLESPACE와 TEMPORARY_TABLESPACE는 유저를 생성할때 지정한 것이며,
이때 테이블스페이스를 지정하지 않으면 오라클은 자동적으로
DEFAULT_TABLESPACE와 TEMPORARY_TABLESPACE를 system으로 이용합니다.



◈ 유저의 Object 정보 조회

- user_objects 데이터 사전을 이용하시면 됩니다.


SQL>col object_name format a25;
SQL>SELECT object_name, object_type
FROM user_objects
WHERE object_type = 'INDEX';

OBJECT_NAME OBJECT_TYPE
------------------------- ------------------
BIANRY_PK INDEX
BINARY_FK INDEX
BOARD_CTNT_LST_FK1 INDEX
BOARD_CTNT_LST_FK2 INDEX
BOARD_CTNT_LST_PK INDEX
BOARD_FK1 INDEX
BOARD_PK INDEX
COMMUNITY_TYPE_IDX INDEX
COMMUNITY_TYPE_PK INDEX
COMM_CTNT_LST_FK1 INDEX
COMM_CTNT_LST_FK2 INDEX
...
27개의 행이 선택되었습니다.

object_type를 보고 싶으면

SQL>SELECT object_type
FROM user_objects
GROUP BY object_type;

OBJECT_TYPE
------------------
INDEX
SEQUENCE
TABLE

'ORACLE' 카테고리의 다른 글

계층구조 쿼리의 예제  (0) 2004.10.15
계층 구조의 조회(Hierarchical Queries)  (0) 2004.10.15
EXECUTE IMMEDIATE를 이용한 Dynamic SQL  (0) 2004.10.15
중복된 RECORD 삭제 방법  (0) 2004.10.15
*새로운 Oracle 9i의 쿼리문*  (0) 2004.10.15
posted by 구름너머 2004. 10. 15. 09:48

Oracle Technical Bulletins No. 10185 참고..

중복된 RECORD 삭제 방법
================================

중복된 RECORD를 삭제하는 방법은 2가지가 있습니다.


방법1)

SQL> CREATE TABLE emp2 AS SELECT distinct * FROM emp;

SQL> DROP TABLE emp;

SQL> RENAME emp2 TO emp;




방법2) 중복된 데이터중에서 ROWID가 큰 값을 제거


SQL> DELETE FROM emp a
WHERE rowid > (SELECT MIN(ROWID)
FROM emp b
WHERE b.empno = a.empno);



en-core에서 본 白面書生(www.okjsp.pe.kr)님의 글도 참고해서 넣었습니다.

방법3) 나중에 들어온 데이터를 살릴경우


SQL> DELETE FROM emp a
WHERE ROWID < (SELECT MAX(ROWID)
FROM emp b
WHERE a.empno = b.empno);

방법4) 레코드가 완전 중복이 아니고 일부 중복인 데이터를 삭제할 경우


SQL>
DELETE /*+ FULL(A) PARALLEL(A, 7)  */
FROM TB_TEST PARTITION(P201407) A
WHERE ROWID IN ( SELECT RID
                            FROM ( SELECT ROWID AS RID, AREA_NO, KUK_NO, SUB_NO,
                                                     RANK() OVER (PARTITION BY AREA_NO, KUK_NO, SUB_NO ORDER BY START_DATE DESC) AS R_NO
                                        FROM TB_TEST PARTITION(P201407) B
                                        WHERE END_DATE = '99991231'
                                        AND     START_DATE < '20140701'
                                       )
                            WHERE R_NO <> 1

                           )
;

설명: 테이블 TB_TEST에서 AREA_NO, KUK_NO, SUB_NO, END_DATE 가 동일하고
        START_DATE가 7월이전인 자료 중에서 START_DATE가 OLD인 자료를 삭제한다.

       즉, AREA_NO, KUK_NO, SUB_NO, END_DATE는 같으나 START_DATE가 다른 자료를 삭제하되   최그것을 살리고 이전것을 삭제하는 경우입니다.

posted by 구름너머 2004. 10. 15. 09:29

*새로운 Oracle 9i의 쿼리문*

1. SQL: 1999 죠인.. 2


1. SQL: 1999 죠인

SQL: 1999 죠인 문법은 Oracle 죠인의 그것과 다음과 같은 점에서 차이가 있습니다.

- 죠인의 형태가 FROM 절에서 명시적으로 지정됩니다.

- 죠인 조건이 WHERE 절의 검색 조건과 구별되어 ON 절에서 명시됩니다.

1.1. SQL: 1999에 정의된 죠인의 형태들

1.1.1. Cross 죠인

- CROSS 죠인은 두 테이블의 곱집합을 생성합니다.

- 이는 두 테이블 간의 Cartesian 곱과 같습니다.

예)

SELECT last_name, department_name

FROM employees CROSS JOIN departments;

1.1.2. Natural 죠인

- NATURAL 죠인은 두 테이블에서 같은 이름을 가진 모든 컬럼에 기반합니다.

- 두 테이블의 대응되는 모든 컬럼에 대해 같은 값을 가지는 행들을 선택합니다.

- 만일 같은 이름을 가지는 컬럼들이 서로 다른 데이터 형을 가질 때에는 오류가 반환됩니다.

- 만일 SELECT * 문법을 사용한다면, 공통 컬럼들은 결과 집합에서 단 한번만 나타납니다.

- 테이블 이름이나 가명 등의 수식자들은 NATURAL 죠인에 사용된 컬럼들을 수식할 수 없습니다.

예)

SELECT department_id, location_id

FROM locations NATURAL JOIN departments;

1.1.3. USING 절을 이용한 죠인

- 만일 여러 개의 컬럼이 이름은 같지만 데이터 형이 모두 일치되지는 않을 때에는,

NATURAL JOIN은 USING 절을 이용하여 동등 죠인에 사용될 컬럼들을 명시하도록 수정될 수 있습니다.

- USING 절에서 참조되는 컬럼들은 SQL 문 어디에서도 수식자(테이블 이름이나 가명)에 의해 수식될 수 없습니다.

- NATURAL 과 USING의 두 키워드는 상호 배타적으로 사용됩니다.

예)

SELECT e.employee_id, e.last_name, d.location_id

FROM employees e JOIN departments d

USING (department_id);

1.1.4. ON 절을 사용하는 죠인

- Natural 죠인의 죠인 조건은 기본적으로 같은 이름을 가진 모든 컬럼들에 대한 동등 조건입니다.

- 임의의 죠인 조건을 지정하거나, 또는 죠인할 컬럼을 명시하기 위해서 ON 절이 사용됩니다.

- ON 절은 죠인 조건과 다른 조건들을 분리합니다.

- ON 절은 코드를 보다 이해하기 쉽게 합니다.

예)

SELECT e.employee_id, e.last_name,

e.department_id, d.department_id,

d.location_id

FROM employees e JOIN departments d

ON (e.department_id = d.department_id);

1.1.5. 복잡한 죠인

- ON 절을 사용함으로써 다음과 같은 것들을 이용한 복잡한 죠인을 만들 수 있습니다.

- 서브쿼리

- AND/OR 연산자

- [NOT] EXISTS

- [NOT] IN

1.1.6. 죠인 조건과 ON 절

- ON 절을 사용함으로써 다른 조건과 죠인 조건을 분리시킬 수 있습니다;

그렇게 하면 코드가 보다 이해하기 쉬워집니다.

- ON 절은 서브쿼리나 논리 연산자 등을 포함한 임의의 조건을 지정할 수 있습니다.

예)

SELECT e.manager_id, e.last_name,

e.department_id, d.location_id

FROM employees e JOIN departments d

ON ((e.department_id = d.department_id)

AND e.manager_id = 102

);

예)Exists의 사용

SELECT department_name, city

FROM locations l JOIN departments d

ON (l.location_id = d.location_id)

AND NOT EXISTS (SELECT 1 FROM employees e

WHERE e.department_id = d.department_id

)

);

예)복수 테이블의 죠인

SELECT employee_id, city, department_name

FROM locations l

JOIN departments d

ON (l.location_id = d.location_id)

JOIN employees e

ON (d.department_id = e.department_id) ;

1.1.7. INNER 대 OUTER 죠인

- SQL: 1999 표준에 의하면 두 테이블을 죠인하여 오로지 대응되는 행들만을 반환하는 것을

INNER 죠인이라 합니다.

- INNER 죠인의 결과와 함께 왼쪽(오른쪽) 테이블의 대응되지 않는 행들도 반환하는 것을

LEFT(RIGHT)OUTER 죠인이라 합니다.

- INNER 죠인의 결과와 함께 LEFT 및 RIGHT OUTER 죠인의 결과까지 모두 반환하는 것을 FULL OUTER 죠인이라 합니다.

) LEFT OUTER 죠인

SELECT e.last_name, d.department_name

FROM employees e LEFT OUTER JOIN departments d

ON (e.department_id = d.department_id)

) RIGHT OUTER 죠인

SELECT e.last_name, d.department_name

FROM employees e RIGHT OUTER JOIN departments d

ON (e.department_id = d.department_id)

) FULL OUTER 죠인

SELECT e.last_name, d.department_name

FROM employees e FULL OUTER JOIN departments d

ON (e.department_id = d.department_id)

2. CASE 수식

2.1. SQL: 1999의 CASE 수식

SQL:1999에는 다음과 같은 형태의 CASE 문들이 있습니다.

- 단순 CASE

- 검색 CASE

- NULLIF

- COALESCE

2.1.1. 단순 CASE 수식

- 단순 CASE 수식은 DECODE 함수와 유사합니다.

- 주어진 수식 내에서 값을 찾고 대체할 수 있습니다.

- 각각의 값에 대해 반환값을 명시할 수 있습니다.

- 비교 연산자를 사용할 수는 없습니다.

예)

SELECT last_name,

(CASE department_id

WHEN 10 THEN 'Administration'

WHEN 20 THEN 'Marketing'

WHEN 30 THEN 'Purchasing'

WHEN 40 THEN 'Human Resources'

ELSE 'N/A'

END) as "Department Names"

FROM employees

ORDER by department_id;

2.1.2. 검색 CASE 수식

- 검색 CASE 수식은 IF… THEN … ELSE 구문과 유사합니다.

- 수식에 대하여 조건부로 값을 찾고 대체할 수 있습니다.

- 각각의 WHEN 조건은 달리 주어지며 복수의 조건이 논리 연산자에 의해 결합될 수 있습니다.

- 조건 수식에 비교 연산자를 사용할 수 있습니다.

- 검색 CASE 수식은 단순 CASE 수식에 비해 보다 유연합니다.

) 검색 CASE문

INSERT INTO raise

SELECT last_name,

CASE

WHEN job_id LIKE 'AD%' THEN '10%'

WHEN job_id LIKE 'IT%' THEN '15%'

WHEN job_id LIKE 'PU%' THEN '18%'

ELSE '20%'

END

FROM employees;

) 검색 CASE문

INSERT INTO raise

SELECT last_name,

CASE

WHEN job_id LIKE 'AD%' THEN '10%'

WHEN job_id LIKE 'IT%' THEN '15%'

WHEN job_id LIKE 'PU%' THEN '18%'

ELSE '20%'

END

FROM employees;