블로그 이미지
'무른모'란 부드럽다라는 뜻을 가진 '무르다'라는 말과 도구, 연장을 뜻하는 '연모'라는 순 우리말의 합성어로 소프트웨어를 말합니다. seanhigher

카테고리

분류 전체보기 (161)
Blog srart (16)
Dev Center (94)
Real Life (13)
Mac life (21)
Naver life (17)
Total633,812
Today36
Yesterday88
데이터베이스에는 수많은 데이터들이 수도없이 들락날락 거린다. 이렇게 수도없이 변경되는 데이터를 효율적으로, 그리고 일관성있게 관리한다는 것은 굉장히 어려운 일중 하나라고 할 수있다. 이런 어려운 일을 도와주는 특별한 기능들이 오라클 속에는 들어있다.



데이터의 순서를 기억해주는 ROWNUM
어떤 테이블을 생성하고 데이터를 입력하던지간에 데이터에는 순서가 정해지게 되는데, 그 순서를 기억하는 보이지 않는 컬럼이 ROWNUM 이다. ROWNUM은 데이터가 테이블에 입력되는 순서대로 순위가 정해지기 때문에 중간에 새로운 데이터가 들어가게 되면 데이터의 순서는 엉망이 되어버린다. 물론 데이터가 들어간 순서를 알고자 한다면 상관이 없지만... 그래서ROWNUM 의 경우는 인라인뷰로 생성하여 데이터를 정렬하고자 할때, 그리고 상위 몇번째까지의 데이터를 얻고자 할때 사용할 수 있다.

SELECT employee_id, last_name, hire_date, salary
    FROM (SELECT employee_id, last_name, hire_date, salary FROM employees ORDER BY salary DESC)
        WHERE ROWNUM <= 5;

위의 쿼리문은 급여가 가장많은 상위 다섯명의 정보를 얻어올 수 있다.


자동으로 순서를 증가시켜주는 SEQUENCE
새로운 데이터가 입력될때마다 자동으로 일정 값 만큼 증가시키고 싶다면 시퀀스 기능을 사용할 수 있다. 시퀀스를 만들고 그것을 테이블의 컬럼에 적용을 하면, 데이터가 새롭게 입력될 때마다 숫자를 입력시키지 않아도 자동으로 순서번호가 들어가게 된다.

CREATE SEQUENCE 시퀀스명;
INSERT INTO 테이블명 VALUES(시퀀스명.NEXTVAL);
SELECT 시퀀스명.CURRVAR FROM DUAL;

시퀀스는 그 자체로 NUMBER 형태의 데이터 타입을 가지기 때문에, 데이터 타입에 맞추어서 시퀀스를 넣어주어야 한다. 일반적으로 시퀀스명은 테이블명_컬럼명_SEQ 의 형태를 갖게 된다. 위에서 첫번째 쿼리문은 시퀀스를 생성하게 되는데, 다양한 조건으로 시퀀스를 생성할 수 있다. START WITH 는 초기값을 나타내고, INCREMENT BY 는 증가값을 나타낸다. MAXVALUE 는 최대값을 나타낸는데, CYCLE 이 YES일 경우 최대값을 넘으면 다시 초기값부터 시작하게 된다. NEXTVAL은 시퀀스의 다음 값을 가져올 수 있고, CURRVAR은 시퀀스가 가지고 있는 현재의 값을 가져오게 된다. 시퀀스를 사용할때 주의해야 할 점은 데이터의 오류가 발생하더라도 시퀀스 번호는 증가한다는 것이다.그리고 그 시퀀스는 다시 되돌릴 수 없다!!


데이터를 빠르게 찾는 방법 INDEX.
일반적으로 데이터를 찾기 위해서는 순차적으로 검색을 하게 된다. 이럴경우, 찾고자 하는 데이터가 테이블의 가장 나중에 있다면 굉장히 많은 시간이 걸리게 될 것이다. 이러한 문제점을 해결하기 위한 방법중의 하나가 인덱스를 사용하는 것이다. 인덱스는 B트리를 사용하여 어떠한 데이터든지 동일한 횟수만에 접근을 하는것이 가능하다. 인덱스를 이용한 데이터의 검색 속도는 그것을 사용하지 않았을때와는 비교하지 못할만큼 비약적이기 때문에, 대용량의 데이터를 사용하는 경우라면 인덱스를 사용하는 것이 일반적이다. 인덱스는 각 데이터를 구분짓는 유일한 데이터여야 하기때문에 일반적으로 기본키를 인덱스로 적용하게 된다.

CREATE INDEX 인덱스명;
CREATE 인덱스명 ON 테이블명(컬럼명);

위와 같이 인덱스를 적용하게 되면 좀더 빠르게 데이터에 접근을 하는 것이 가능하다. 일반적으로 인덱스명은 INDEX_테이블명_컬럼명 의 형식으로 생성하게 된다.

Posted by seanhigher

댓글을 달아 주세요

여러개의 테이블에서 원하는 데이터를 얻어내기 위해서는 조인 연산을 통해서 결과를 얻어낼 수 있다. 하지만, 똑같은 데이터를 얻어내기 위해서 매번 조인 연산을 해야 한다는 것은 매우 불합리한 일임을 쉽게 느끼게 될 것이다.



VIEW.
뷰는 실제로 존재하는 테이블과는 조금 차이가 있다. 테이블은 데이터를 갖고 있지만, 뷰는 갖고 있지 않다. 그리고 조인 연산으로 데이터를 가져오게 되면, 식의 조건에 맞는 테이블의 형태로 데이터를 보여주게 된다. 이렇게 조인과 셀렉트 연산으로 보여지는 가상의 테이블을 영구적으로 만들어 놓는 것을 뷰라고 정의할 수 있다.


뷰 생성하기.
뷰를 생성하는 방법은 테이블을 만드는 방법과 비슷하다.

CREATE VIEW 뷰이름;
CREATE OR REPLACE VIEW 뷰이름;

두번째의 쿼리는 동일한 이름의 뷰가 이미 정의되어 있을 경우 이전의 것에 그대로 덮어서 생성을 하게 된다. 이전것과는 상관없이 무조건 생성하는 것이다. 하지만 이것은 단지 뷰만 만들어 놓으것이다. 어떠한 형태와 구조도 없고, 당연히 데이터도 없다. 아직은 아무런 쓸모가 없는 것이다. 이뷰에 데이터를 넣어주어야 뷰로서의 기능을 발휘하게 된다.

CREATE VIEW 뷰이름 AS SELECT * FROM 대상테이블;

위의 쿼리문을 실행하게 되면, 대상테이블에 있던 데이터가 새로운 뷰 안에 포함되게 된다. 하지만, 이렇게 테이블을 그대로 뷰로 옮겨놓는 것은 뷰의 가능성을 무시하는 처사라고 할 수있다. 일반적으로는 AS 절 이후의 셀렉트문을 여러개의 테이블에서 조인을 하거나, 원하는 컬럼들만 추출하여 새로운 테이블을 만든것과 같은 효과를 주어 사용을 하게 된다.

CREATE VIEW 뷰이름 AS
    SELECT e.employee_id, e.last_name, e.salary, e.department_id, d.department_name
        FROM employee e, department d WHERE e.department_id = d.department_id
            ORDER BY salary DESC;

위와 같은 방법으로 뷰를 생성해 놓으면 다시는 부서의 이름을 얻어내기 위해 조인을 하는 수고는 덜게 될 것이다.


인라인 뷰의 사용.
테이블을 조인하기에도 적당하지 않고, 뷰를 만들기에도 한번만 사요을 해야 하는 것이 있다면... 서브쿼리와 비슷한 형태로 인라인 뷰 기능을 이용하면 된다. 서브 쿼리는 어떠한 결과 값을 반환하여 WHERE, HAVING 과 같은 조건절에 사용되는 반면, 인라인뷰는 조건에 맞는 테이블 자체를 반환하기 때문에 FROM 절에 값으로 사용할 수 있다.

SELECT employee_id, last_name, hire_date
    FROM (SELECT employee_id, last_name, hire_date, FROM employee ORDER BY hire_date)
        WHERE employee_id <= 50;

인라인 뷰는 위와 같은 형식으로 사용하는 것이 가능하다. 조금더 발전적인 형태로는 인라인 뷰와, 서브쿼리, 조인연산을 적절하게 사용하게 된다면, 원하는 데이터라면 어떠한 것이라도 가져오는 것이 가능할 것이다.

Posted by seanhigher

댓글을 달아 주세요

데이터 베이스는 데이터가를 안전하게 지키는 것이 가장 중요하기 때문에, 일정 부분에 대해서는 실수도 보장을 해주는데, 이것을 롤백이라고 한다. 그리고 작업을 이루는 단위는 트랜잭션이라고 한다.



트랜잭션단위
데이터베이스에서 이루어지는 작업의 최소단위를 트랜잭션 단위라고 한다. 테이블을 생성하거나, 데이터를 삭제하거나, 제약조건을 추가하거나, 이런 모든 작업들을 하나의 트랜잭션이라고 할 수 있다. 데이터베이스에서 이런 작업을 기록하는 이유는, 사용자, 또는 시스템상의 실수를 보상하기 위해서이다. 만일 은행 계좌에서 돈을 인출하는 과정을 하나의 트랜잭션이라고 할때, 돈을 인출하고, 그것을 확인하는 과정에서 시스템이 정지 되었다고 가정해보자. 그렇다면, 돈을 인출한 것이 사용자에게 확인이 되지 않았기 때문에 인출하기 이전의 상태로 돌아가야 한다. 하지만, 이미 이루어진 작업에 대해서 돌이킬 수 없다면, 어느 누구도 보상해주지 않는것이다. 이런 상황을 되돌려 주는 기능이 롤백 기능이다.


COMMIT, ROLLBACK, 그리고 SAVEPOINT
그렇다고 데이터베이스의 모든 작업이 무한정으로 저장되는 것은 아니다. COMMIT이라는 명령어를 받아들이기 전까지의 행동을 기억하게 된다. COMMIT 이라는 것은 일종의 확인으로, 한번 COMMIT을 하게 되면 더이상은 되돌리지 않겠다는 확인의 의사 표현과 동일하다. 그래서 한번 ROLLBACK을 하게 되면 이전에 COMMIT을 한 이후 최초의순간으로 돌아가게 되는 것이다. 하지만, 이런식으로 작업을 되돌리기에는 허술한 감이 없잖아 있는데, SAVEPOINT를 주어 단계적으로 작업을 되돌리는 것이 가능하다. 물론 그 사이에 COMMIT을 하게 된다면 모든것은 그냥 '인정' 되어버리고 만다.

삭제 1;
SAVEPOINT S1;
삭제 2;
삭제 3;
SAVEPOINT S2;
삭제 4;
삭제 5;
ROLLBACK TO S2;

위와 같은 순서대로 쿼리문을 진행하게 되면, 삭제된 4, 5는 원래대로 돌아오게 된다. 그리고 한번더 ROLLBACK S1을 실행시키면 삭제된 2, 3 도 원래대로 돌아오게 된다. 하지만 ROLLBACK S2 를 하지 않은 상태에서 S1 을 곧바로 실행한다면 S2 의 상태로는 되돌릴 수 없게 된다. 순차적인 회복만 가능한 것이다.


테이블을 복사하는 방법.
테이블을 복사하는 방법에는 두가지가 있다. 테이블의 형식만 복사하는 방법과, 테이블과, 데이터를 통채로 복사하는 방법이다.

CREATE TABLE 새로운테이블명 AS SELECT * FROM 대상테이블명 WHERE 1=0;
DESC 새로운테이블명;
CREATE TABLE 새로운테이블명 AS SELECT * FROM 대상테이블명;

테이블을 복사하기 위해서는 AS 절을 사용할 수 있다. 새로운 테이블명으로 테이블을 생성하고, 그 안에 들어갈 내용을 AS 를 사용해 표시해 주면 된다. 만일 조건으로 1=0 을 할경우엔 테이블의 구조만을 복사하게 되고, 조건이 없을 경우에는 모든 데이터까지 한번에 복사가 된다. DESC 명령은 테이블의 구조를 간편하게 볼 수있도록 해준다. 혹여나 테이블의 구조만 복사한 후에 테이블에서 데이터만을 복사해 넣고 싶다면, 다음과 같이 사용하는 것이 가능하다.

INSERT INTO 새로운테이블명 SELECT * FROM 대상테이블명;

위의 쿼리는 대상테이블의 모든 데이터를 새로운테이블에 복사하게 된다. 물론 새로운테이블과 대상테이블의 테이블 구조는 동일해야 한다.

Posted by seanhigher

댓글을 달아 주세요

이미 만들어진 테이블을 수정하기 위해서는, 테이블을 삭제하거나, 컬럼을 수정, 삭제 하는 방법이 있다. 데이터를 직접 수정하는 방법도 가능하다.



테이블의 데이터 변경하기.
테이블에 데이터를 넣기 위해서는 INSERT INTO 명령을 사용할 수 있다. 이미 테이블에 들어 있는 데이터를 수정하기 위해서는 UPDATE 명령어를 사용할 수 있다. 데이터를 삭제하기 위해서는 DELETE 명령을 사용할 수 있다.

UPDATE 테이블명 SET 컬럼명 = 값, 컬럼명 = 값, WHERE 조건식;
DELETE FROM 테이블명 WHERE 조건식;

데이터를 수정하는 UPDATE문을 사용할때는 각각의 컬럼에 데이터를 수정할 수 있다. 각 컬럼값에 대해서만 데이터를 수정할 수 있다. 그리고 WHERE 절을 사용해 조건실을 주어야 원치 않는 데이터가지 변경되는 것을 막을 수 있다. DELETE 는 해당 조건에 맞는 레코드를 삭제하게 된다. 테이블 전체를 삭제하기 위해서는 위의 DELETE 쿼리문에서 WHERE 절만 제거하면 해당 테이블을 삭제한다.

TRUNCATE TABLE 테이블명;

TRUNCATE 는 테이블을 완전삭제하게 되는데, 히스토리 기능과 비슷한 롤백 기능까지 사용할 수 없기때문에 TRUNCATE 는 사용하기 전에 좀더 신중하게 사용해야 한다.


연결되어 있는 데이터를 삭제하는 방법.
만일 다른 테이블에 외래키로 참조되고 있는 데이터를 삭제하려고 한다면, 삭제가 되지 않을 것이다. 이렇게 외래키로 연결되어 있는 데이터를 삭제하기 위해서는 참조하고 있는 기본키 데이터를 삭제한 후 삭제하는방법과, 제약조건을 삭제한 후 데이터를 삭제하는 방법이 있다. 이 두가지 방법 모두 데이터베이스의 기본인 무결성 원칙을 해치는 방법이기 때문에, 직접적으로 사용되지는 않는다. 하지만, 삭제하고자 하는 데이터를 새로운 기본키를 참조하게 만들고 삭제하는 방식으로 데이터를 삭제한 후, 다시 입력하는 우회적인 방법을 사용하는 것이 가능하다.

Posted by seanhigher

댓글을 달아 주세요

조인을 하게되면 여러개의 테이블에서 데이터를 한번에 참조하는것이 가능하다. 자신의 테이블에서 데이터를 참조하거나, 셀렉트의 결과를 다시 참조하는 형태의 서브쿼리로 좀더 다양한 방법으로 참조하는 것이 가능하다.



셀프조인
가끔은 이런 조건이 필요한 경우가 있다. 'King'이라는 사람의 매니저 이름을 알고 싶다면.. 매니저의 아이디는 직원 아이디로 사용될 수도 있다. 자신의 테이블에 없는 정보를 얻기 위해서는 조인을 해야 하는데... 자기 자신의 테이블도 조인을 하는것이 가능하다. 그것이 셀프조인인데, 일반적인 조인의 사용방법과 같은 방법으로 사용할 수 있다. 주의해야 할 점은 같은 테이블을 참조하는 것이기 때문에 꼭 다름 이름으로 앨리어스를 주어야 하고, 각 컬럼마다 테이블 이름을 명시해 주어야 에러가 나지 않게 된다. 조건을 명시할때도 어떤 테이블을 참조할것인 조금은 고민을 해야 한다.

SELECT e1.last_name, e2.last_name
  FROM employees e1 JOIN employees e2 ON e1.manager_id = e2.employee_id
    WHERE e1.last_name = 'King';

위의 것은 표준조인방식이지만, WHERE 문을 사용하는 방식으로 추가하는것도 동일하게 적용된다.



서브쿼리
다른 테이블의 데이터를 참조하는 방법에는 조인을 하는 방법 외에도 서브쿼리를 사용하는 방법이 있다. 하나의 쿼리문을 사용해서 나온 결과값을 가지고, 또 다른 쿼리문의 조건으로 사용하는 것이다. 사용하는방법은 매우 간단하다. 단지 괄호문 안에 넣어주면 된다. 당연한 이야기일 수도 있겠지만, 서브쿼리문은 WHERE 과 HAVING 과 같은 조건문에서만 사용이 가능하다.

SELECT employee_id, last_name, salary
  FROM employees
    WHERE salary > ( SELECT MAX(salary) FROM employee WHERE deparment_id = 20 );

위의 쿼리문을 해석하면, '부서번호가 20인 사원들중 가장높은 급여보다 더 많은 급여를 받는 사람들의 정보를 출력하라'이다. 앞의 조건은 '부서번호가 20인 사원들중 가장높은 급여'를 구해서 그 급여보다 높은 사람들을 구하는 방법으로 나눌 수 있다. 하나의 결과를 다른 쿼리문에 적용을 하는 것이다. 이것은 전형적인 서브쿼리이다. 위의 조건식은 다음과 같은 방법으로도 표현이 가능하다.

    WHERE salary > ALL( SELECT salary FROM employee WHERE deparment_id = 20 );

MAX() 함수를 사용하는 경우에는 가장 큰 값을 반환하지만, 위의 경우에는 참조하는 모든 값보다 높은것을 의미한다. 부서번호가 20인 모든 사람들의 급여보다 높은 사람들을 비교하는 것이다. 결국은 부서번호가 20인 사람들 중에서 가장 높은 급여를 비교하게 되는 것이다. 이것과 반대로 ANY를 사용할 수 있는데, 모든 사람들이 아니라, 어떤 사람들의 급여보다 높으면 되는 것이다. 쉽게 ALL은 조건에서 자기 자신을 포함하지 않지만, ANY는 자기 자신을 포함한다고 할 수 있다.

서브쿼리를 사용할때 주의해야 할점은 서브쿼리에서 반환하는 내용과 비교하고자 하는 내용의 형식과 갯수가 일치해야 한다는 것이다. 만일 각 부서별로 가장 많은 급여를 받는 사람들의 명단을 알고자 한다면..

SELECT last_name, salary, job_id
  FROM employees
    WHERE (salary, job_id) IN ( SELECT MAX(salary), job_id FROM employees GROUP BY gob_id);

서브쿼리에서 MAX 와 job_id 를 반환하기 때문에 조건에서도 salary 와 job_id 를 함께 비교해야 한다. 또 반환하는 내용이 둘 이상일 경우에는 IN 또는 NOT IN 을 사용하여 조건을 비교하는 것이 가능하다.

Posted by seanhigher

댓글을 달아 주세요

데이터베이스에서 가장 중요한 역할을 하는 것은 '조인' 연산이라고 할 수 있다. 데이터베이스에 많은 데이터가 있지만, 그 데이터를 얼마나 효율적으로 가져오는지가 중요하다. 이 과정이 조인이 필요한 이유이다.



JOIN 연산
일반적으로 데이터베이스에 있는 데이터를 가져오기 위해서는 'SELECT'문을 사용하게 되는데, 기본적인 셀렉트 문을 사용해서는 하나의 테이블안에 있는 데이터밖에는 가져오지 못한다는 문제점이 있다. 조인 연산은 둘 이상의 테이블에 있는 데이터를 가져올 수 있도록 해준다. 만일 employees 테이블에 'King' 이라는 사람의 부서 이름을 구하고자 한다. 하지만, employees 테이블에는 department_id 만 있을뿐 부서의 이름은 찾을 수가 없다. 하지만, departments 라는 테이블에서 department_id를 통해 부서의 이름을 알 수는 있다. JOIN 연산을 하지 않는다면, employees 에서 department_id 를 검색한후 department_id 를 가지고 departments 테이블에서 찾아낸 department_id 에 맞는 부서의 이름을 검색하여 결과를 얻어내야 할 것이다. 하지만, JOIN 연산을 사용한다면 다음과 같이 한번에 표현하는 것이 가능하다.

SELECT employees.last_name, departments.department_name
  FROM employees JOIN departments ON employees.department_id = departments.department_id
    WHERE employees.last_name = 'King';



기본적인 JOIN.
표준 조인방법은 위의것과 같다. JOIN 에 데이터를 추가하고자 하는 테이블의 이름을 써넣고, ON 에는 두 테이블을 이어주는 관계조건을 명시해주면 된다. 위에서는 테이블의 이름을 계속써야 하기때문에 조금 불편한면이 있다. 각 테이블명에 앨리어스 기능을 사용하는 것이 가능하다. 'FROM employees e' 라고 하면 employees 를 써야 하는 부분에는 'e' 를 써주면 된다. e.last_name과 같이 사용할 수 있다.

SELECT e.last_name, d.department_name
  FROM employees e JOIN departments d ON e.department_id = d.department_id
    WHERE e.last_name = 'King';

조금은 더 간단하게 사용하는 것이 가능하다. 위의 방법은 표준 조인이라고 불린다. 그리고 위의 방법 외에 WHERE 문에 조건을  더 주는 방법으로 JOIN문을 사용하지 않고 조인을 사용하는 것이 가능하다.

SELECT e.last_name, d.department_name
  FROM employees e, departments d
    WHERE e.last_name = 'King' AND e.department_id = d.department_id;



좀더 많이 조인하기.
그렇다면 두개이상의 조인은 어떻게 해야할까? 밑의 WHERE 을 사용하는 방법을 사용한다면 AND 를 사용해서 조건을 추가함으로써 쉽게 조인 테이블을 추가할 수 있다.

SELECT e.last_name, d.department_name
  FROM employees e, departments d, locations l
    WHERE e.last_name = 'King' AND e.department_id = d.department_id AND d.location_id = l.location_id;

위의 방법보다는 조금 더 복잡하게 보일 수 있겠지만, 표준조인 방식으로는 JOIN 과 ON 을 추가하여 조인 테이블을 추가해야 한다.

SELECT e.last_name, d.department_name
  FROM employees e JOIN departments d ON e.department_id = d.department_id
    JOIN locations l ON d.location_id = l.location_id
      WHERE e.last_name = 'King';

WHERE 보다는 쿼리문이 조금 길어진다는 단점이 있지만, 원하는 조건을 WHERE 문에만 쓸 수 있어서 찾고자 하는 조건을 좀더 명확하게 알 수 있다는 장점이 있다. 하지만, 어떠한 방식을 취하는것은 개발자의 몫이다.



모든 데이터를 출력하는 OUTER JOIN.
HR 계정에서 다음의 쿼리문을 실행해보자.

SELECT employee_id, last_name, hire_date  FROM employees e, departments d
    WHERE TO_CHAR(hire_date, 'YYYY-MM') BETWEEN '1999-01' AND '1999-06';

11개의 결과값이 나오는 것을 확인할 수 있다. 그렇다면 조인 연산을 이용해서 부서명까지 출력을 해보면...

SELECT e.employee_id, e.last_name, e.hire_date, d.department_name
  FROM employees e, departments d
    WHERE e.department_id = d.department_id
      AND TO_CHAR(hire_date, 'YYYY-MM') BETWEEN '1999-01' AND '1999-06';

결과값이 뭔가 이상하다. 11개의 행이 나와야 하는데, 10개의 행밖에 나오지 않는다. 그 이유가 무엇일까?? 이유는 employee 테이블에 있는 데이터 중에서 department_id 값이 널인것이 있기 때문이다. 부서명을 출력하기 위해서 조인연산을 사용했지만, department_id 가 없는 것에 대해서는 조건이 만족하지 않기 때문에 아예 결과가 출력되지 않는 것이다. 그렇다면 그 결과는 영영 출력할 수 없는 것일까? 아웃터 조인이라는 방법은 이러한 문제점을 해결해 준다. employees 에는 있지만, departments 에 없는 데이터를 출력하기 위해서는 WHERE 조건을 e.department_id = d.department_id(+) 라고 '(+)'만 추가해주면 된다. 그렇게 되면 원하던 11개의 결과를 얻을 수 있을 것이다.

    WHERE e.department_id = d.department_id(+)

하지만 표준 조인을 사용하는 방식에서는 조금 다르게 사용을 해야 한다. JOIN 대신에 LEFT JOIN 이나 RIGHT JOIN 을 사용해야 한다.

  FROM employees e LEFT JOIN departments d ON e.department_id = d.department_id

표준조인에서는 위의 방법과는 다르게 데이터가 있는 employees 쪽으로 표시를 해주어야 한다. 만일 위의 employees 와 departments 의 위치가 바뀐다면 RIGHT 를 사용해야 할 것이다.

  FROM department d RIGHT JOIN employees e ON e.department_id = d.department_id

가끔은 표준이 아닌것이 훨씬 더 편하게 사용되는것이 많은것 같은 생각도 문득 든다.

Posted by seanhigher

댓글을 달아 주세요

데이터베이스는 수많은 데이터를 다루게 된다. 그렇기 때문에 꼭 지켜져야 할 조건이 있는데, 그중 가장 중요한 조건은 데이터의 무결성을 유지해야 한다는 것이다.



데이터의 무결성.
데이터 무결성의 사전적인 의미는 저장된 데이터값과 그것이 표현하는 현실 세계의 실제값이 일치하는 정확성이라고 할 수 있다. 무결성에는 널 , 무결성, 참조, 도메인, 키, 관계, 개체 무결성 이 있다. 이런 데이터 무결성은 테이블에서 제약조건을 선언함으로써 지켜질 수 있다.


제약조건.
제약조건은 각 컬럼에서 데이터들이 갖을 수 있는 특징을 표현하게 된다. 제약조건으로 표현되는 것에는, 기본키 조건, 외래키, 유니크, 낫 널, 체크 조건을 줄 수 있다. 제약조건을 명시하는 방법에는 컬럼 옆에 조건을 표시하는 컬럼레벨 방식과, 따로 조건을 명시하는 테이블 레벨의 방식으로 나뉠 수 있다. 기본키 조건인 PRIMARY KEY 조건은 다른 레코드와 중복이 있으면 안되며, 테이블 안에서 레코드를 구분짓는 유일한 조건이 된다. 외래키 조건인 FOREIGN KEY 조건은 다른 테이블의 기본키를 참조하여 다른 테이블과의 관계를 형성하는 조건이 된다. UNIQUE 조건은 동일한 테이블 내에서 중복이 있지 않도록 한다. 아이디 같은 경우 키본키는 아니지만, 중복이 있지 않도록 할 수 있다. NOT NULL 은 해당 컬럼에 널값이 들어가지 않도록 한다. 회원 정보를 입력할때, 회원의 이름은 꼭 포함되어야 한다. CHECK는 특정한 데이터만 입력되도록 한다. 성별을 입력할 경우 남성과 여성에 대해서만 데이터를 입력받게 되고 그 이외의 데이터에 대해서는 입력이 허용되지 않게 조건을 줄 수 있다.


테이블에 제약조건 주기.
테이블을 생성하면서 제약조건을 포함할 수 있다.

CREATE TABLE member_table (
member_id VARCHAR2(10) PRIMARY KEY,
member_name VARCHAR2(20) UNIQUE NOT NULL,
member_gender VARCHAR2(1),
member_group VARCHAR2(10) REFERENCES group(group_id)
);

위의 방식은 컬럼레벨 방식으로 제약조건을 선언하는 것이다. 한개의 컬럼에 여러개의 제약조건이 있을경우복합적으로 표현하는 것이 가능하다. 하지만, 컬럼레벨 방식에서는 CHECK 조건과, 두개이상을 기본키로 설정하는 복합키를 선언하는 것이 불가능하다. 이것은 테이블레벨 방식을 사용해서만 선언이 가능하다.

CREATE TABLE member_table (
member_id VARCHAR2(10),
member_name VARCHAR2(20) NOT NULL,
member_gender VARCHAR2(1),
member_group VARCHAR2(10) REFERENCE group(group_id),

CONSTRAINT MEMBER_ID_PK PRIMARY KEY(member_id),
CONSTRAINT MEMBER_NAME_UN UNIQUE(member_name),
CONSTRAINT MEMBER_GENDER_CH CHECK(member_gender IN('F', 'M')),
CONSTRAINT MEMBER_GROUP_FK FOREIGN KEY(member_group) REFERENCES group(group_id)
);

테이블 레벨방식에서 제약조건을 선언하기 위해서는 CONSTRAINT를 사용해야 한다. 또 CONSTRAINT를 사용하면 제약조건에 이름을 선언할 수 있다. 이름을 선언하게 되면 제약조건을 수정하는 것이 가능하다. 한가지 NOT NULL 제약조건은 컬럼레벨 방식에서만 선언이 가능하고, CHECK 와 복합키는 테이블 레벨 방식에서만 선언이 가능하다는 것을 기억해야 한다. 그리고 컬럼레벨 방식에서도 CONSTRAINT 를 사용하여 이름을 지정하는 것이 가능하다.

member_id VARCHAR2(10) CONSTRAINT MEMBER_ID_PK PRIMARY KEY


제약조건 수정, 추가, 삭제.
제약조건을 수정하는것도 가능하다. 하지만, 제약조건에 맞는 이름을 알고 있어야 한다. 제약조건은 수정하기 위해서는 이름을 통해서 접근이 가능하기 때문이다. 혹시 제약조건의 이름을 기억하지 못한다면 제약조건 테이블을 통해서 알 수 있다.

SELECT CONSTRAINT_NAME, CONSTRAINT_TYPE, TABLE_NAME, R_CONSTRAINT_NAME
FROM USER_CONSTRAINTS WHERE TABLE_NAME = 테이블명;

제약조건을 수정하는 방법은 컬럼을 수정하는 방법과 거의 비슷하다.

ALTER TABLE 테이블명 ADD 제약조건(컬럼);
ALTER TABLE 테이블명 MODIFY 컬럼 제약조건;
ALTER TABLE 테이블명 DROP 제약조건이름;

제약조건은 데이터베이스에 있어서 꼭 있어야 하는 요소중의 하나이다. 이제약조건을 제대로 명시하지 않고, 지키지 않는다면, 데이터베이스로의 기능을 상실하게 될 것이다.
Posted by seanhigher

댓글을 달아 주세요

데이터베이스의 데이터들은 테이블안에 저장되어 있다. 데이터베이스를 사용하기 위해서는 가장먼제 테이블을 만들어야 하는 것이다. 데이터베이스를 사용하기 위한 시작점인 것이다.



테이블의 구조.
테이블을 만들기 위해서는 테이블이 어떤 구조로 되어 있는지 알아야 한다. 테이블은 테이블의 이름이 있고, 각 테이블은 각 항목을 나타내는 컬럼이 있다. 각 컬럼들에는 그 컬럼에 맞는 이름과 데이터 타입을 갖게 된다. 컬럼으로 이루어진 테이블에는 하나의 레코드 형식으로 새로운 데이터들이 들어가게 된다.


테이블 만들기
테이블을 만드는 방법은 매우 간단하다. CREATE() 명령문을 사용하면 되는데, 테이블의 기본 구조를 이루는 컬럼들을 함께 선언하여 생성할 수 있다.

CREATE TABLE 테이블이름 (
컬럼이름    데이터타입,
컬럼이름    데이터타입
);

컬럼은 필요한 만큼 여러개 생성하는 것이 가능하다. 쿼리문을 사용하여 테이블을 생성하게 되면, 테이블은 기본적인 구조를 갖게 되고, 그 구조에 맞추어 데이터를 넣을 준비가 되는 것이다.


테이블에 데이터 넣기.
테이블에 데이터를 넣기 위해서는 INSET INTO 명령을 사용해야 한다. 테이블의 구조에 맞게 데이터를 넣는 방법과, 원하는 테이블에만 데이터를 넣을 수 있다.

INSERT INTO 테이블명 VALUES (데이터, 데이터, 데이터);
INSERT INTO 테이블명(컬럼명, 컬럼명) VALUES(데이터, 데이터);

만일 넣고자 하는 데이터가 모든 컬럼에 만족한다면 위와 같이 한번에 입력을 하는 것이 가능하다. 하지만, 특정 컬럼에 대해서만 데이터를 넣고자 한다면, 두번째 쿼리문처럼 원하는 커럼명을 명시해주어, 특정 컬럼에만 데이터를 넣을 수 있다.


컬럼을 추가, 수정, 삭제.
테이블을 만든후, 추가를 하거나, 수정및, 삭제를 해야 한다면, 어떻게 해야 할까? 가장 간단한 방법은 테이블을 삭제하고 다시 만들면 된다. 하지만, 이미 데이터가 포함되어 있다면, 데이터도 다시 넣어야 하기 때문에 곤란한 상황이 될 것이다. 테이블의 컬럼들을 수정하기 위해서는 ALTER 라는 명령어를 사용하여 수정을 하는것이 가능하다.

ALTER TABLE 테이블명 MODIFY 컬럼명    데이터타입;
ALTER TABLE 테이블명 ADD 컬럼명    데이터타입;
ALTER TABLE 테이블명 DROP COLUMN 컬럼명;

MODIFY, ADD, DROP 는 각각 원래있던 컬럼을 수정하고, 추가하고, 삭제하는 역학을 한다. 이 명령을 사용하면 포함되어 있는 데이터들도 당연히 삭제가 된다.

Posted by seanhigher

댓글을 달아 주세요

  1. 2010.08.20 12:03 ssjh312  댓글주소  수정/삭제  댓글쓰기

    좋은글 감사합니다.

셀렉트문과 조건문을 통해 원하는 데이터를 뽑아내었다 할찌라도 원하는 데이터들이 뒤죽박죽으로 되어 있다면 사용을 하기가 매우 어려울 것이다. 데이터베이스를 사용하는 의미조차 찾기 어려워지는 것이다.



데이터들 정렬하기.
데이터를 정렬하는 방법은 매우 간단하다. 기본적인 셀렉트문을 사용한 후 마지막에 ORDER BY 구문을 사용해서 정렬 조건을 주면 된다.

SELECT last_name FROM employees ORDER BY last_name;
SELECT last_name, salary FROM employees WHERE salary > 10000 ORDER BY salary DESC;
SELECT last_name, salary FROM employees WHERE salary > 10000 ORDER BY last_name DESC, salary;

첫번째의 쿼리문은 이름을 가나다 순을 정렬해서 보여준다. ORDER BY 를 사용한 정렬에서, 정렬 형식을 지적해주지 않는다면 기본적으로 올림차순으로 정렬이 된다. 두번째 쿼리에서 처럼 급여가 10000 이상인 사람들을 급여가 높은 순으로 정렬을 하고 싶다면 ORDER BY 항목의 마지막에 'DESC' 를 추가하면 내림차순으로 정렬을 하는것이 가능하다. 세번째의 쿼리문같이 여러가지 항목으로 정렬을 하는것도 가능한데, 먼저 열거된 항목으로 정렬이 된 후, 그 안에서 정렬이 되는 형식을 따른다.



그룹별 검색을 위한 그룹함수.
이런 경우가 있다. 특정 부서에 있는 사람들의 평균이나, 총합을 구하고 싶을때, 각 그룹별로 구하고 싶을때. 많은 양의 데이터를 관리하게 될때, 이러한 요구는 충분히 많이 필요하게 될 것이다. 오라클에서는 이러한 부분들을 이미 함수로 만들어 준비해 두었다. 이전에 문자열로 변환하는 TO_CHAR(), 이나 숫자로 변환하는 TO_NUMBER() 도 하나의 함수이다. 함수를 사용하는데 있어서 주의해야 할것이 있는데, 그 함수가 그룹을 지원하는가에 대해서 생각해 보아야 한다는 것이다. 그룹별로 나뉘어진 데이터를 보고자 하는데, 그를 충족시키는 조건이 오지 않는다면 데이터베이스는 사용자의 의도대로 데이터를 보여주지 못할 것이다.

SELECT AVG(salary) FROM employees GROUP BY department_id;

부서별로 급여의 평균을 구하고자 한다면 위와 같은 쿼리문을 작성해서 사용할 수 있다. GROUP BY 는 그룹을 구분짓는 역할을 한다. 그룹별 구분을 짓는 GROUP BY 절을 사용할때는 SELECT 부분에는 그룹바이로 나뉘어진 항목이나, 그룹 함수를 사용한 항목만 표기하는 것이 가능하다. 위의 쿼리에서는 그룹함수 AVG() 가 사용되었기 때문에 아무런 문제 없이 출력이 가능하다. 위의 쿼리문에 추가할 수 있는 항목은, 또다른 그룹함수나, GROUP BY 항목으로 나뉘어져있는 department_id 외에는 올 수가 없다. 그룹 함수로 사용되는 또 다른 함수에는 항목의 총 합을 구하는 SUM() 함수, 항목내에서 가장 큰 값을 반환하는 MAX() 함수, 가장 작은 값을 반환하는 MIN() 함수가 있고, 그룹내에 포함되는 숫자를 알고 싶다면 COUNT() 함수를 사용하면 각 그룹에 몇개의 항목이 포함되어 있는지 알 수 있다.



그룹별 조건달기.
GROUP BY 절을 통해 각 그룹별 항목을 출력하는 것이 가능하다는 것을 알게 되었다. 일반적인 항목에 대해서는 WHERE 을 통해서 조건을 명시하는 것이 가능하였는데, 그룹을 조건으로 해야 할때도 WHERE 을 사용하는것이 가능할까? 가능할것 같기도 하지만, 실제론 그렇지 않다. 그룹별로 조건을 나누게 될때, 각 그룹안에 항목들을 구분지으며, 조건을 포함시킨다는 것은 실로 불가능하기 때문이다. 그래서 GROUP BY 를 통해 구분된 그룹에 조건을 추가하기 위해서는 HAVING 이라는 항목을 사용해야 한다.

SELECT department_id, AVG(salary) FROM employees GROUP BY department_id HAVING department_id > 30;

위의 쿼리문에서는 각 그룹별로 평균을 구하는데, 그 그룹 아이디가 30 보다 큰 그룹에 대해서만 평균을 구하는 것을 의미한다. 그룹을 구분짓는 조건에 대해서는 HAVIG 절을 사용했다는 것을 알 수 있다.



자주 사용되는 유용한 함수들.
오라클의 함수에는 그룹함수 이외에도 유용하게 쓰이는 함수들이 있다. 그리고 그 함수들은 중첩해서 사용하는 것이 가능하다. ROUND() 라는 함수는 자릿수를 제한하는 기능을 가진 함수인데, 평균을 구하는 AVG() 함수와 함께 사용하여 불필요한 소수점 이하의 자릿수를 줄이는 것이 가능하다.

SELECT department_id, ROUND(AVG(salary), 2) FROM employees GROUP BY department_id;

ROUND() 함수는 첫번째로 받은 인자를 두번째로 받은 수의 소수자릿수만큼만 표현을 해준다. 위에서 처럼 '2'를 입력했다면 소수 셋째자리에서 반올림하여 소수 둘째자리까지만 표현을 해주게 된다. 소수점을 표현하고 싶지 않다면 두번째 자리에 '0'을 입력하면 소수점 이하의 자리에서는 반올림이 이루어진다. 그리고 음수로 표현할 경우에는 10의자리 100의 자리로 점점 자릿수가 올라간다. 만일 '-2'를 입력한다면 10의 단위에서 반올림한 수가 출력되게 되는 것이다.

WIDTH_BUCKET() 함수는 네개의 인자값을 갖게 된다. 첫번째 인자는 입력한 값이 되고, 두번째와 세번째는 각각 최소값과, 최대값이 된다. 그리고 마지막은 최소값과 최대값 사이를 나누는 분할비가 된다. 이것은 일정한 등급을 분류할때 사용될 수 있다.

SELECT WIDTH_BUCKET(82, 0, 100, 10) FROM DUAL;

위와 같은 쿼리문을 실행한다면, '0'에서 '100' 까지를 10개의 단계로 나눈 후 입력값 '82'가 포함된 단계인 '9' 를 반환하게 된다.

NVL() 함수는 첫번째 값이 'NULL' 값을 가질 경우, 아무것도 표현하지 않는대신 다른 문자로 표현할 수 있도록 해준다.

SELECT commission_pct FROM employees;
SELECT NVL(commission_pct, 0) FROM employees;

첫번째 쿼리는 커미션이 없을 경우 없다는 의미의 '-'를 출력하지만, 두번째는 '-' 대신에 '0'이라는 숫자를 출력해준다. 주의해야할 점은 'NULL' 값을 대신하는 것은 그 데이터 타입과 동일해야 한다는 것이다.

FLOOR() 함수는 소수점 이하의 수를 내림 해주는 기능을 갖고, CELL() 함수는 소수점 이하의 수를 올림 해주는 기능을 갖고 있다. 이 두개의 함수는 무조건 정수형태의 값만을 리턴하게 된다. 그리고 추가적으로 TRUNC() 라는 함수는 두번째 인자로 내림하고자 하는 자릿수를 정할 수 있다. 인자값 만큼의 소수자리수를 남기로 내림을 실행하게 된다.

MOD() 함수는 첫번째 인자를 두번재 인자를 나눈 나머지값을 반환하는데, 자바에서의 MOD 연산자와 동일한 역할을 한다.
LOWER(), UPPER() 함수는 각각 인자로 받아들여진 문자열을 모두 소문자로, 대문자로 변환시켜준다.

SUBSTR() 함수는 문자열을 분리해주는 기능을 가지고 있다. 첫번째 인자로 받은 문자열을 두번째 인덱스 번호에서부터, 세번째 숫자만큼의 문자수만큼 잘라내어 반환해준다.

SELECT SUBSTR('HELLO BYE', 7, 3) FROM DUAL;

'HELLO BYE'에서 'BYE'만을 추출하기 위해서는 위와 같은 쿼리문을 사용할 수 있다. 7번째 인덱스인 'B'에서부터 세번째인 'E'까지의 문자열을 나타낸다.

Posted by seanhigher

댓글을 달아 주세요

데이터베이스에는 수많은 데이터들이 저장되어 있다. 그 데이터를 불러오지 않으면 그것은 모두 쓸모없는 데이터들이 된다. 데이터베이스에서 데이터를 불러오기 위해서는 SELECT 라는 명령문을 사용하게 된다.



SELECT문 사용하기
셀렉트는 데이터를 출력하기 위한 가장 기본적인 명령이다. 데이터베이스에서의 기초라고 할 수 있다. 오라클레서 제공하는 XE 버전을 설치하게 되면 'HR' 계정이 있는데, 이것은 데이터베이스에 대한 연습을 하기 위해 이미 테이블들이 생성되어 있기 때문에, 기본적인 데이터베이스에 대한 연습을 하기에는 충분하다. 먼저 테이블의 목록을 보기 위해서 다음과 같이 입력하도록 한다.

SELECT * FROM TAB;

이것은 해석하자면 'TAB' 라는 테이블의 모든 정보를 보여달라는 것이다. SELECT '컬럼명' FROM '테이블명' 의 형식으로 사용되는 것이다. '*' 은 모든컬럼을 표시하라는 의미이고, 'TAB' 은 테이블명이다. 'TAB' 테이블은 사용자가 만드는 것이 아니라 데이터베이스에서 자동으로 만들어지는데, 그 사용자의 테이브에 대한 정보를 가지고있다. 위의 쿼리문을 입력하면 'HR'계정이 가지고 있는 테이블에 대한 정보를 보여줄 것이다.

보여지는 테이블 중에서 employees 테이블의 정보를 보고 싶다면..

SELECT * FROM employees;

위의 쿼리는 'employees' 테이블에 있는 모든 컬럼들과 정보를 보여줄 것이다. 이중에서 특정 부분(직원 번호, 이름, 급여) 만을 보고 싶다면 컬럼명을 명시하여 검색을 할 수 있다.

SELECT employee_id, last_name, salary FROM employees;

각 컬럼들은 콤마를 이용해 구분하도록 한다.



좀더 세밀한 검색하기.
기본 쿼리문에 WHERE 을 통해서 좀더 상세한 조건으로 원하는 결과를 검색을 할 수 있다. 특정한 데이터 값을 갖는다던지, 큰것과 작은것을 비교하는 것이 가능하다.

SELECT employee_id, last_name, salary FROM employees WHERE last_name = 'King';
SELECT employee_id, last_name, salary FROM employees WHERE salary > 10000;
SELECT employee_id, last_name, salary FROM employees WHERE last_name IN ('King', 'Abel', 'Smith');

위의 첫번째쿼리문은 'King'이란 이름을 갖고 있는 데이터를 보여주고, 두번째는 급여가 20000 보다 높은 사람의 데이터를 보여준다. 마지막의 쿼리문은 이름이 'King', 'Able', 'Smith'인 모든 사람을 보여주게 된다. 그 이름이 포함되지 않은 사람을 검색하고 싶다면 'IN' 대신에 'NOT IN'을 사용하면 된다. 그리고 조건이 여러개가 있을경우에는 함께 AND 와 OR 을 사용하여 조건을 추가하는 것이 가능하다.

SELECT employee_id, last_name, salary FROM employees WHERE last_name = 'King' AND salary > 10000;
SELECT employee_id, last_name, salary FROM employees WHERE last_name = 'King' OR salary > 10000;

급여가 10000 이상 20000 이하인 사람의 데이터를 검색하기 위해서는 부등호와 AND 를 조합하여 사용할 수 있지만, 'BETWEEN ~ AND' 를 사용해서도 표현할 수 있다.

SELECT employee_id, last_name, salary FROM employees WHERE salary >= 10000 AND salary <= 20000;
SELECT employee_id, last_name, salary FROM employees WHERE salary BETWEEN 10000 AND 20000;

위의 두 식은 같은 결과 값을 출력하게 된다. 일부 데이터중에는 값이 없는 것이 있을 수도 있는데, 이것은 'NOT NULL' 과 'IS NOT NULL' 의 식으로 표현할 수 있다. 직원들 중에서 커미션이 없는 직원들을 보고싶다면..

SELECT employee_id, last_name, salary, commission_pct FROM employees WHERE commission_pct IS NULL;

위와 같은 방식으로 쿼리문을 작성할 수 있을 것이다.



문자열을 비교하기.
직원의 이름들 중에서 'K'를 포함하는 사람들 검색하고 싶다면 어떤 조건을 주어야 할지 고민이 될 것이다. 특정 문자를 포함하는 조건을 주고 싶을땐, 'LIKE' 를 사용해서 검색할 수 있다.

SELECT employees_id, last_name, salary FROM employees WHERE last_name LIKE '%k%';
SELECT employees_id, last_name, salary FROM employees WHERE last_name LIKE '__k%';

'%' 기호는 한자리 이상의 모든 문자를 의미한다. '%k%' 는 'k' 를 포함하는 모든 문자열이 되는 것이다. '_'는 한 문자를 가르킨다. '__k%' 는 세번째 문자가 'k'인 모든 문자를 의하는 것이다. 이제 문자열에 대해서도 원하는 결과를 도출할 수 있게 되었다.



Date 로 검색하기.
오라클의 데이터 타입에는 문자열(char, varchar), 숫자(number), 날짜(date) 형식이 있다. Date 타입이 기본적으로 보여주는 형식은 'YY/MM/DD'의 모습을 가지고 있다. 현재의 시간을 나타내는 데이터로 'SYSDATE'를 사용할 수 있는데, 매우 세밀한 시간의 정보까지 가지고 있어서 자세한 시간의 출력을 하는것까지 가능하다.

SELECT SYSDATE FROM DUAL;
SELECT TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS') FROM DUAL;
SELECT TO_CHAR(10000, '$999,999') FROM DUAL;

위의 쿼리문에서는 간단하게 날까지만 출력을 하는 것이 가능하다. 쿼리문에서 사용된 'DUAL'은 테이블이 없는 상태에서 데이터를 출력하고자 할때, 가상의 테이블을 만들어주는 역할을 한다. 아래의 쿼리문은 현재의 시간을 '년도-월-날 시간:분:초'의 형식을 출력형식을 지정해주어 나타낼때 사용된다. 이때 사용되는 TO_CHAR() 라는 함수는 날짜의 형식뿐만 아니라 세번째의 쿼리문처럼 통화의 형태를 나타내는 것도 가능하다. 이와 비슷하게 TO_NUMBER() 라는 함수는 인자로 들어온 문자열을 숫자로 바꾸어주는 기능을 가지고 있다. 물론 안에 포함되는 문자는 숫자의 형태를 가지고 있어야 한다.

문자열 형태도 변환된 날자 데이터는 일반적인 문자열 검색과 동일하게 검색하는 것이 가능하다. 원하는 년도나, 월에 포함된 데이터를 선택한다던지, 일정기간내의 데이터를 검색하는 것도 가능하다.

SELECT employee_id, last_name, to_char(hire_date, 'YYYY/MM/DD') FROM employees
WHERE TO_CHAR(hire_date, 'YYYY/MM/DD') BETWEEN '1997/0101' AND '1997/12/31';

SELECT employee_id, last_name, to_char(hire_date, 'YYYY/MM/DD') FROM employees
WHERE TO_CHAR(hire_date, 'YYYY/MM/DD') LIKE '1997%';

위의 두 쿼리문은 1997년에 속한 데이터들을 출력해줄 것이다.
Posted by seanhigher

댓글을 달아 주세요

최근에 달린 댓글

글 보관함