2021. 05. 06(목) TIL
Database
다중행함수(그룹함수)
- 조회된 행들의 집합그룹에 적용되어 그룹당 하나의 결과를 생성하는 함수다.
- 집합그룹이란
- 테이블 전체 또는 그룹화된 테이블의 행들을 말한다.
- 집합그룹의 예
- 사원테이블전체 혹은 부서별 평균임금
- 직종별 전체 급여
- 관리자별 관리직원수
- 입사년도별 입사한 사원수
- 급여등급별 사원수
- 사용시 주의사항
- 그룹함수는 where절에서 사용할 수 없다.
- 그룹함수와 그룹함수가 아닌 표현식을 select절에 같이 적을 수 없다
- 그룹함수의 중첩은 한번만 허용된다.
- group by 절에 등장한 표현식은 그룹함수와 같이 select절에 적을 수 있다.
그룹함수의 종류
- count(*)
- 조회된 모든 행의 갯수를 반환한다.
- count(컬럼 혹은 표현식)
- 조회된 행에서 지정된 컬럼의 값이 null이 아닌 행의 갯수를 반환한다.
- sum(컬럼 혹은 표현식)
- 조회된 행에서 지정된 컬럼의 값의 합계를 반환한다.(null값은 무시된다.)
- avg(컬럼 혹은 표현식)
- 조회된 행에서 지정된 컬럼의 값의 평균을 반환한다.(null값은 무시된다.)
- min(컬럼 혹은 표현식)
- 조회된 행에서 지정된 컬럼의 값의 최소값을 반환한다.(null값은 무시된다.)
- max(컬럼 혹은 표현식)
- 조회된 행에서 지정된 컬럼의 값의 최대값을 반환한다.(null값은 무시된다.)
- variance(컬럼 혹은 표현식)
- 조회된 행에서 지정된 컬럼의 값의 분산을 반환한다.(null값은 무시된다.)
- stddev(컬럼 혹은 표현식)
- 조회된 행에서 지정된 컬럼의 값의 표준편차를 반환한다.(null값은 무시된다.)
테이블의 행을 그룹화하기
- group by 절을 사용해서 지정된 컬럼의 값이 같은 값을 가지는 행끼리 그룹화할 수 있다.
- group by절의 작성 규칙
select 컬럼혹은표현식, 그룹함수(), 그룹함수()
from 테이블명
[where 조건식]
[group by 컬럼혹은표현식]
[order by 컬럼명]
- group by절은 행 그룹화 기준을 결정하는 값을 가진 컬럼을 지정한다.
- select 절에서 group by절에 지정한 컬럼은 그룹함수와 같이 사용할 수있다.
- select 절에서 사용된 그룹함수는 group by로 그룹화된 각각의 그룹마다 실행된다.
- 집합그룹이란
- 테이블 전체 또는 그룹화된 테이블의 행들을 말한다.
- 집합그룹의 예
- 사원테이블전체 혹은 부서별 평균임금
- 직종별 전체 급여
- 관리자별 관리직원수
- 입사년도별 입사한 사원수
- 급여등급별 사원수
- 사용시 주의사항
- 그룹함수는 where절에서 사용할 수 없다.
- 그룹함수와 그룹함수가 아닌 표현식을 select절에 같이 적을 수 없다
- 그룹함수의 중첩은 한번만 허용된다.
- group by 절에 등장한 표현식은 그룹함수와 같이 select절에 적을 수 있다.
- 조회된 모든 행의 갯수를 반환한다.
- 조회된 행에서 지정된 컬럼의 값이 null이 아닌 행의 갯수를 반환한다.
- 조회된 행에서 지정된 컬럼의 값의 합계를 반환한다.(null값은 무시된다.)
- 조회된 행에서 지정된 컬럼의 값의 평균을 반환한다.(null값은 무시된다.)
- 조회된 행에서 지정된 컬럼의 값의 최소값을 반환한다.(null값은 무시된다.)
- 조회된 행에서 지정된 컬럼의 값의 최대값을 반환한다.(null값은 무시된다.)
- 조회된 행에서 지정된 컬럼의 값의 분산을 반환한다.(null값은 무시된다.)
- 조회된 행에서 지정된 컬럼의 값의 표준편차를 반환한다.(null값은 무시된다.)
select 컬럼혹은표현식, 그룹함수(), 그룹함수()
from 테이블명
[where 조건식]
[group by 컬럼혹은표현식]
[order by 컬럼명]
그룹함수 실행결과를 필터링하기
- having절은 group by 절을 사용해서 행을 그룹화하고, 각 그룹에 그룹함수를 실행한 결과를 필터링할 때 사용한다.
- 일반적으로 행을 필터링할 때는 where절을 사용한다.
- where과 having
- where
- 행을 필터링한다.
- 그룹함수를 조건식에 사용할 수 없다.
- having
- 그룹화된 그룹에 그룹함수 적용한 후에 계산된 결과로 필터링을 한다.
- 그룹함수를 조건식에 사용할 수 있다.
- where
- having절의 작성규칙
select column, 그룹함수
from table
[where 조건식]
[group by 컬럼혹은표현식]
[having 그룹함수적용결과를 필터링하는 조건식]
[order by 컬럼]
-- 다중행 함수
-- employees 테이블에 등록된 모든 사원들의 수를 조회하기
select count(*)
from employees;
-- 60번 부서에 소속된 사원들의 수 조회하기
select count(*)
from employees
where department_id = 60;
-- 커미션을 받는 사원들의 수를 조회하기
select count(*)
from employees
where commission_pct is not null;
select count(commission_pct)
from employees;
-- 60번 부서에 소속된 사원들이 받는 급여의 총합, 최저급여, 최고급여, 평균급여를 조회하기
select sum(salary) 급여총합, min(salary) 최저급여, max(salary) 최고급여, avg(salary) 평균급여
from employees
where department_id = 60;
-- group by를 사용해서 테이블의 행들을 그룹화하기
-- 같은 부서에 소속된 사원들끼리 그룹화한 다음, 그룹함수를 적용해보기
SELECT department_id, COUNT(*)
FROM employees
GROUP BY department_id;
-- 부서별로 사원들을 그룹화한 다음, 부서별 급여총합, 급여평균을 조회하기
SELECT department_id, SUM(salary), ROUND(AVG(salary))
FROM employees
GROUP BY department_id;
-- 부서별로 사원들을 그룹화한 다음, 부서별 급여총합, 급여평균을 조회하기
-- 부서이름, 부서별 급여총합, 부서별 급여평균을 조회함
SELECT D.department_name, SUM(salary), ROUND(AVG(salary))
FROM employees E, departments D
WHERE E.department_id = D.department_id
GROUP BY D.department_name;
-- 부서별로 사원들을 그룹화하고, 같은 부서에 소속된 사원들을 직종으로 다시 그룹화 한 다음
-- 해당 그룹에 속하는 사원들의 숫자를 조회하기
SELECT department_id, job_id, COUNT(*)
FROM employees
GROUP BY department_id, job_id
ORDER BY 1, 2;
-- 급여별로 사원들을 그룹화 했을 때, 각 급여별 사원수를 조회하기
SELECT TRUNC(salary, -3) salary, COUNT(*)
FROM employees
GROUP BY TRUNC(salary, -3)
ORDER BY salary;
-- 급여별 사원수를 조회하기
SELECT (TRUNC(salary/5000) + 1) * 5000 || '미만' sal, COUNT(*)
FROM employees
GROUP BY TRUNC(salary/5000)
ORDER BY TRUNC(salary/5000);
-- 부서별 사원수를 조회했을 떄 사원수가 5미만인 부서의 아이디와 사원수를 조회하기
-- groupby가 있을때 having은 없어도되지만 having만 존재해서는 안된다.
SELECT department_id, COUNT(*)
FROM employees
GROUP BY department_id
HAVING COUNT(*) < 5;
-- 2007년에 입사한 사원들의 수를 직종아이디로 기준잡아 집계했을 때
-- 3명 이상 채용된 직종의 아이디와 사원수를 조회하기
SELECT job_id, COUNT(*)
FROM employees
WHERE hire_date >= to_date('2007/01/01') and hire_date < to_date('2008/01/01')
GROUP BY job_id
HAVING COUNT(*) >= 3
ORDER BY job_id;
-- 부서별 사원수를 집계했을 떄 사원수가 10명 이상인 부서의 아이디, 사원수를 조회하기
SELECT department_id, COUNT(*)
FROM employees
GROUP BY department_id
HAVING COUNT(*) >= 10;
-- with절을 사용해서 쿼리의 실행속도를 개선 및 쿼리의 가독성을 높이기
WITH employees_count
AS (
SELECT department_id dept_id, count(*) cnt
FROM employees
GROUP BY department_id
)
SELECT A.dept_id, B.department_name, A.cnt
FROM employees_count A, departments B
WHERE A.dept_id = B.department_id
AND A.cnt >= 5
ORDER BY A.dept_id;
package demo2.app;
import demo2.dao.UserDao;
import demo2.vo.User;
public class SimpleUserApp {
public static void main(String[] args) {
UserDao userDao = new UserDao();
// // 새로운 사용자정보 등록하기
// User user = new User();
// user.setId("hong");
// user.setPassword("zxcv1234");
// user.setName("홍길동");
// user.setEmail("[email protected]");
// user.setPhone("010-1234-5678");
//
//
// userDao.insertUser(user);
// System.out.println("새로운 사용자 정보가 등록되었습니다.");
// 사용자 정보 조회
User savedUser = userDao.getUserById("hong");
System.out.println("아이디 : " + savedUser.getId());
System.out.println("비밀번호 : " + savedUser.getPassword());
System.out.println("사용자명 : " + savedUser.getName());
System.out.println("전화번호 : " + savedUser.getPhone());
System.out.println("이메일 : " + savedUser.getEmail());
System.out.println("사용자 상태 : " + savedUser.getStatus());
System.out.println("사용자 정보 생성일 : " + savedUser.getCreatedDate());
// 사용자 정보 변경하기
// "hong" 아이디를 가진 사용자의 이메일, 전화번호 변경하기
User savedUser2 = userDao.getUserById("hong");
savedUser2.setEmail("[email protected]");
savedUser2.setPhone("010-5678-1234");
userDao.updateUser(savedUser2);
}
}
오라클의 데이터 타입
-
VARCHAR2(size)
- 가변길이 문자 데이터, 최대값: 4000
- size범위내에서 실제 데이터의 크기만큼만 저장공간을 사용한다.
- 예) 이름, 주소, 과목명, 상품명, 뉴스제목
-
CHAR(size)
- 고정길이 문자 데이터, 최대값: 2000
- size크기만큼의 저장공간을 무조건 사용한다.
- 예) 주민번호, 학번, 수강과목코드
-
LONG
- 가변길이 대용량 문자 데이터, 최대값: 2GB
- 현재는 잘 사용되지 않음
- 테이블당 하나밖에 사용할 수 없다.
- 제약조건을 정의할 수 없다.
- order by나 group by에 포함시킬 수 없다.
-
CLOB
- 가변길이 대용량 문자 데이터(Character Large OBject), 최대값: 4GB
- 예) 블로그의 본문, 신문기사, 논문
-
NUMBER(p, s)
- 가변길이 숫자 데이터
- p:십진수의 총 갯수, s:소숫점이하 자릿수
-
DATE
- 날짜 및 시간 데이터
- 예) 입사일, 가입일, 주문날짜, 이체날짜, 신청날짜 ...
-
TIMESTAMP
- 날짜 및 시간 데이터, 소수점 이하 초까지 포함한다.
-
BLOB
- 가변길이 대용량 이진 데이터(Binary Large OBject), 최대값: 4GB
- 예) 그림, 영상, 게임파일
-
ROWID
- 테이블에서 행의 고유주소를 나타내는 64진수 숫자데이터
select rowid, department_id, department_name
from departments;
rowid departmet_id department_name
--------------------------------------------------------
AAAEAWAAEAAAACtAAA 10 Administration
AAAEAWAAEAAAACtAAB 20 Marketing
AAAEAWAAEAAAACtAAC 30 건희 영업팀
오브젝트번호 파일번호 블록번호 데이터번호
AAAEAW AAE AAAACt AAA
AAAEAb AAE AAAADN AAA
- 오브젝트번호
- 해당 데이터가 속해있는 데이터베이스 객체(테이블)의 번호
- 데이터베이스 객체마다 고유하다.
- 파일번호
- 해당 데이터가 위치하고 있는 테이블스페이스 파일번호
- 블록번호
- 파일내부의 블록번호
- 데이터번호
- 데이터가 저장되어있는 데이터 디렉토리 슬롯 번호
데이터 정의어(DDL)
- 오라클 데이터베이스 객체 생성, 변경, 삭제에 사용되는 명령어
- CREATE, ALTER, DROP, TRUNCATE
주요 데이터베이스 객체
- 테이블
- 데이터의 기본 저장단위, 행과 열로 구성되어 있다.
- 뷰
- 하나 이상의 테이블을 사용해서 만든 가상의 테이블
- 시퀀스
- 일련번호 생성기
- 인덱스
- 검색성능을 향상시키기 위해 데이터에 대한 색인을 가지고 있다.
- 동의어
- 객체에 대한 다른 이름을 제공한다.
테이블
- 테이블과 컬럼의 이름규칙
- 문자로 시작, 30자까지 가능, A-Za-z0-9_$# 만 허용,
- 오라클 예약어 사용금지
- 테이블 생성하기
CREATE TABLE 테이블명 (
컬럼명 데이터타입(크기) [DEFAULT 기본값],
...
)
- 테이블 삭제
DROP TABLE 테이블명
- 테이블 변경
- 컬럼추가
ALTER TABLE 테이블명 ADD (컬럼명 데이터타입(크기) [DEFAULT 기본값]);
- 컬럼수정
ALTER TABLE 테이블명 MODIFY (컬럼명 테이터타입(크기) [DEFAULT 기본값]);
- 컬럼삭제
ALTER TABLE 테이블명 DROP 컬럼명;
- 테이블 이름 변경
RENAME 테이블명 TO 새테이블명
- 테이블 절단하기
TRUNCATE TABLE 테이블명;
-- truncate는 테이블에서 모든 행을 제거한다.
-- 해당 테이블이 사용하는 저장공간을 해제한다.
-- truncate로 제거된 행은 rollback할 수 없다.
시퀀스
- 일련번호를 자동으로 생성하는 데이터베이스 객체다.
- 기본키 값(행을 대표하는 값)을 생성하는데 주로 사용됩니다.
- 시퀀스 생성
CREATE SEQUENCE 시퀀스명;
-- 1부터 1씩 증가하는 번호가 발행된다.
CREATE SEQUENCE 시퀀스명
[INCREMENT BY a] a씩 증가한다.
[START WITH b] b부터 시작한다.
[{MAXVALUE c | NOMAXVALUE}] c가 최대값이다.
[{MINVALUE d | NOMINVALUE}] d가 최소값이다.
[{CYCLE | NOCYCLE}] 최대값/최소값이 도달했을 때 반복여부를 결정한다.
[{CACHE e | NOCACHE}] 일련번호를 e개 만큼 미리 할당해서 메모리에 캐시하거나, 캐시를 활용하지 않는다.
- 시퀀스 생성하기 예제
CREATE SEQUENCE 시퀀스명
INCREMENT BY 1
START WITH 1
NOMAXVALUE
NOMINVALUE
NOCYCLE
CACHE 20;
- 시퀀스의 삭제
DROP SEQUENCE 시퀀스명
- 시퀀스의 수정
ALTER SEQUENCE 시퀀스명
[INCREMENT BY a]
[{MAXVALUE c | NOMAXVALUE}]
[{MINVALUE d | NOMINVALUE}]
[{CYCLE | NOCYCLE}]
[{CACHE e | NOCACHE}]
-- START WITH를 제외한 나머지 설정을 변경할 수 있다.
- 시퀀스의 사용
- 시퀀스명.NEXTVAL
- 새로운 일련번호를 반환한다.
- 시퀀스명.CURRVAL
- 현재 연결된 세션에서 nextval를 통해서 발행했던 번호를 다시 .
- CURRVAL을 사용하려면 해당 시퀀스에 대한 NEXTVAL이 실행된 후에만 가능한다.
뷰
- 테이블 혹은 다른 뷰를 기반으로 하는 가상의 테이블(논리적인 테이블)이다.
- 특징
- 물리적인 저장공간을 가지지 않는다.
- INSERT, UPDATE, DETELE 작업의 수행이 불편하다.
- 목적
- 복잡한 SQL문을 간단하게 작성하기 위해서 사용
- 데이터의 엑세스를 제한하기 위해서 사용(데이터에 대한 보안성 강화)
- 동일한 데이터로부터 다양한 결과를 얻기 위해서 사용
- 종류
- 단순 뷰
- 한 테이블에서만 데이터를 가져온다.
- 함수 또는 데이터 그룹을 사용하지 않았음
- DML(INSERT/UPDATE/DELETE가 가능은 하다)
- 복합 뷰
- 여러 테이블에 데이터를 가져온다.
- 함수 또는 데이터 그룹을 포함하고 있음
- DML 거의 불가능하다.
- 뷰 생성
CREATE [OR REPLACE] VIEW 뷰이름
AS 서브쿼리
WITH READ ONLY
-- 서브쿼리는 가상의 테이블이 포함할 데이터를 조회하는 SELECT문
- 뷰 수정
CREATE OR REPLACE VIEW 뷰이름
AS 서브쿼리
-- 뷰이름을 수정하려는 기존 뷰이름과 동일하게 지정하면 된다.
- 뷰 삭제
DROP VIEW 뷰이름
인라인 뷰
- SELECT 문의 FROM절에 서브쿼리를 정의하고, 이 서브쿼리로 조회된 결과를 가상의 테이블로 취급하고, 별칭을 부여한 것
- 데이터베이스 객체가 아니다.
- 형식
SELECT A.column, A.column, A.column
FROM (SELECT column, column, column, ...
FROM table1
WHERE 조건식) A
WHERE 조건식
인덱스(색인)
- 데이터 행의 검색 속도를 향상시키기 위해서 사용되는 데이터베이스 객체다.
- 데이터의 위치를 빠르게 찾는 신속한 경로 엑세스 방법을 사용하여 디스크 I/O를 줄여 준다.
- 인덱스는 테이블과 독립적으로 존재한다.
- 한 번 생성된 인덱스는 Oracle이 자동으로 유지 관리한다.
- 테이블이 삭제되면 그 테이블의 데이터를 색인화하고 있는 인덱스도 같이 삭제된다.
- 인덱스 생성
- 자동 생성
- 테이블 정의할 때 primary key 제약조건, unique 제약조건이 정의된 컬럼의 값들은 자동으로 인덱스가 생성된다.
- 수동 생성
- 사용자가 행에 대한 엑세스 시간을 줄이기 위해서 특정 열을 대상으로 인덱스를 생성할 수 있다.
- 인덱스 생성하기
CREATE INDEX 인덱스명
ON 테이블명 (컬럼명, ....)
- 인덱스 삭제하기
DROP INDEX 인덱스명
- 함수 기반 인덱스 생성하기
CREATE INDEX 인덱스명
ON 테이블명 (오라클함수)
- 인덱스를 생성이 필요한 경우
- where절이나 조인조건에 자주 사용되는 경우
- 컬럼이 매우 다양한 값을 포함하고 있는 경우
- 데이터가 아주 많은 테이블을 대상으로 조회작업을 했을 때 대부분의 조회작업에서 검색되는 행이 전체 데이터의 2%~4%미만인 경우
- 인덱스 생성이 필요하지 않는 경우
- 테이블이 작은 경우
- 테이블이 자주 갱신되는 경우
- 인덱스화된 열이 표현식의 일부로 사용되는 경우
- where절의 조회 조건으로 자주 사용되지 않는 경우
- 대부분의 조회작업에서 전체 데이터의 2%~4%이상 검색되는 경우
트리거
- 특정 테이블에 INSERT, UPDATE, DELETE 작업이 수행될 때 자동으로 실행되는 것이다.
- 트리거는 데이터베이스 객체다.
- 종류
- 행 트리거
- 테이블의 데이터가 변경될 때 실행되는 트리거
- 문장 트리거
- 영향을 받는 행이 없더라고 실행되는 트리거
- 특정 시간에 실행되는 트리거
- 형식
CREATE OR REPLACE TRIGGER 트리거명
{BEFORE | AFTER} -- 트리거 실행 싯점
{INSERT, UPDATE, DELETE} ON 테이블명 -- 이벤트종류
FOR EACH ROW -- 데이터 행의 변화가 생길 때 마다 실행된다
BEGIN
실행할 SQL
END;
-
트리거의 접두어(OLD, NEW)
- OLD, NEW 접두어는 행 트리거에서만 사용가능하다.
- 트리거 수행문에서 변경이 발생한 행의 이전값, 변경된(추가된 값)을 사용할 수 있다.
작업 OLD값 NEW값 INSERT NULL 추가된 값 UPDATE 갱신전의 값 갱신후의 값 DELETE 삭제전의 값 NULL
- 작성예
- 주문정보 이력 저장하기
- 주문정보가 추가되거나, 주문상태가 변경될 때마다 그 이력을 저장하기
- 주문정보 이력을 저장하는 테이블 생성하기
create table tb_order_history (
order_no number(7),
cust_no number(5),
order_status varchar2(20),
order_update_date date
);
- 주문정보 추가/변경시 실행될 트리거 생성하기
CREATE OR REPLACE TRIGGER order_history_trigger
AFTER
INSERT OR UPDATE ON tb_orders
FOR EACH ROW
BEGIN
insert into tb_order_history
(order_no, cust_no, order_status, order_update_date)
values
(:new.order_no, :new.cust_no, :new.order_status, sysdate);
END;
- 트리거 활성화 비활성화 하기
ALTER TRIGGER 트리거명 ENABLE;
ALTER TRIGGER 트리거명 DISABLE;
- 트리거 삭제하기
DROP TRIGGER 트리거명;
-- 테이블에 저장된 각 행들의 ROWID 조회하기
SELECT ROWID, department_id, department_name
FROM departments;
select rowid, department_id, department_name
from departments;
-- 1부터 시작하는 시퀀스 생성하기
CREATE SEQUENCE product_seq
START WITH 1
NOCACHE;
SELECT product_seq.NEXTVAL FROM dual;
-- 상품테이블 생성하기
CREATE TABLE sample_products (
product_no number(8) primary key,
product_name varchar2(200) not null,
product_maker varchar2(100) not null,
product_category varchar2(100) not null,
product_price number(8) not null,
product_discount_price number(8) not null,
product_stock number(5) default 100,
product_sold_out char(1) default 'N',
product_created_date date default sysdate
);
-- 상품테이블에 상품정보 저장하기
INSERT INTO sample_products
(product_no, product_name, product_maker, product_category, product_price, product_discount_price)
values (product_seq.nextval, 'iphone12 plus', 'apple', '스마트폰', 1400000, 1200000);
-- 새로운 일련번호 조회하기
SELECT PRODUCT_SEQ.nextval FROM dual;
-- 현재 시퀀스의 일련번호 조회하기
SELECT product_seq.currval FROM dual;
------------- 퀴즈
-- 사원아이디, 이름, 소속부서 아이디, 소속부서명을 조회하기
SELECT e.employee_id, e.first_name, d.department_id, d.department_name
FROM employees E, departments D;
-- 60번부서에 소속된 사원들의 사원아이디, 이름, 급여, 직종아이디, 직종제목, 직종최저급여, 직종최고급여를 조회하기
SELECT e.employee_id, e.first_name, e.salary, j.job_id, j.job_title, j.min_salary, j.max_salary
FROM employees E, jobs J
WHERE e.department_id = 60
AND e.job_id = j.job_id;
-- 모든 사원들의 사원아이디, 이름, 급여, 급여등급을 조회하기
SELECT e.employee_id, e.first_name, e.salary, s.grade
FROM employees E, salary_grade S
WHERE e.salary >= s.min_salary and e.salary <= s.max_salary
ORDER BY e.employee_id;
-- 60번부서에 소속된 사원들의 사원아이디, 이름, 상사의 이름을 조회하기
SELECT e.employee_id, e.first_name, m.first_name
FROM employees E, employees M
WHERE e.employee_id = m.manager_id
AND e.department_id = 60;
-- 부서관리자가 있는 부서의 부서아이디, 부서명, 부서관리자 아이디, 부서관리자이름을 조회하기
SELECT d.department_id, d.department_name, d.manager_id, e.first_name
FROM departments D, employees E
WHERE d.department_id = e.department_id
AND d.manager_id = e.employee_id
AND d.manager_id is not null;
-- 부서관리자가 있는 부서의 부서소재지 도시명을 중복없이 조회하기
SELECT DISTINCT l.city
FROM departments D, locations L
WHERE d.manager_id is not null
AND d.location_id = l.location_id;
-- 소속부서명이 'Sales'이고, 급여등급이 'A'나 'B'에 해당하는 사원들의 아이디, 이름, 급여, 급여등급을 조회하기
SELECT e.employee_id, e.first_name, e.salary, s.grade
FROM employees E, departments D, salary_grade S
WHERE e.department_id = d.department_id
AND d.department_name = 'Sales'
AND e.salary >= s.min_salary and e.salary <= s.max_salary
AND s.grade in ('A', 'B');
-- 60번 부서에 소속된 사원들의 평균급여를 조회하기
SELECT AVG(salary)
FROM employees
WHERE department_id = 60;
-- 직종아이디별 사원수를 조회하기
SELECT job_id, COUNT(*)
FROM employees
GROUP BY job_id;
-- 급여 등급별 사원수를 조회하기
SELECT s.grade, COUNT(*)
FROM employees E, salary_grade S
WHERE e.salary >= s.min_salary AND e.salary < s.max_salary
GROUP BY s.grade;
-- 2007년 입사한 사원들의 월별 입사자 수를 조회하기
SELECT to_char(hire_date, 'MM') MM, COUNT(*)
FROM employees
WHERE hire_date >= to_date('2007/01/01') and hire_date < to_date('2008/01/01')
GROUP BY to_char(hire_date, 'MM')
ORDER BY to_char(hire_date, 'MM');
Author And Source
이 문제에 관하여(2021. 05. 06(목) TIL), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://velog.io/@eastgun_/2021.-05.-06목-TIL
저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
VARCHAR2(size)
- 가변길이 문자 데이터, 최대값: 4000
- size범위내에서 실제 데이터의 크기만큼만 저장공간을 사용한다.
- 예) 이름, 주소, 과목명, 상품명, 뉴스제목
CHAR(size)
- 고정길이 문자 데이터, 최대값: 2000
- size크기만큼의 저장공간을 무조건 사용한다.
- 예) 주민번호, 학번, 수강과목코드
LONG
- 가변길이 대용량 문자 데이터, 최대값: 2GB
- 현재는 잘 사용되지 않음
- 테이블당 하나밖에 사용할 수 없다.
- 제약조건을 정의할 수 없다.
- order by나 group by에 포함시킬 수 없다.
CLOB
- 가변길이 대용량 문자 데이터(Character Large OBject), 최대값: 4GB
- 예) 블로그의 본문, 신문기사, 논문
NUMBER(p, s)
- 가변길이 숫자 데이터
- p:십진수의 총 갯수, s:소숫점이하 자릿수
DATE
- 날짜 및 시간 데이터
- 예) 입사일, 가입일, 주문날짜, 이체날짜, 신청날짜 ...
TIMESTAMP
- 날짜 및 시간 데이터, 소수점 이하 초까지 포함한다.
BLOB
- 가변길이 대용량 이진 데이터(Binary Large OBject), 최대값: 4GB
- 예) 그림, 영상, 게임파일
ROWID
- 테이블에서 행의 고유주소를 나타내는 64진수 숫자데이터
select rowid, department_id, department_name
from departments;
rowid departmet_id department_name
--------------------------------------------------------
AAAEAWAAEAAAACtAAA 10 Administration
AAAEAWAAEAAAACtAAB 20 Marketing
AAAEAWAAEAAAACtAAC 30 건희 영업팀
오브젝트번호 파일번호 블록번호 데이터번호
AAAEAW AAE AAAACt AAA
AAAEAb AAE AAAADN AAA
- 해당 데이터가 속해있는 데이터베이스 객체(테이블)의 번호
- 데이터베이스 객체마다 고유하다.
- 해당 데이터가 위치하고 있는 테이블스페이스 파일번호
- 파일내부의 블록번호
- 데이터가 저장되어있는 데이터 디렉토리 슬롯 번호
- 오라클 데이터베이스 객체 생성, 변경, 삭제에 사용되는 명령어
- CREATE, ALTER, DROP, TRUNCATE
주요 데이터베이스 객체
- 테이블
- 데이터의 기본 저장단위, 행과 열로 구성되어 있다.
- 뷰
- 하나 이상의 테이블을 사용해서 만든 가상의 테이블
- 시퀀스
- 일련번호 생성기
- 인덱스
- 검색성능을 향상시키기 위해 데이터에 대한 색인을 가지고 있다.
- 동의어
- 객체에 대한 다른 이름을 제공한다.
테이블
- 테이블과 컬럼의 이름규칙
- 문자로 시작, 30자까지 가능, A-Za-z0-9_$# 만 허용,
- 오라클 예약어 사용금지
- 테이블 생성하기
CREATE TABLE 테이블명 (
컬럼명 데이터타입(크기) [DEFAULT 기본값],
...
)
- 테이블 삭제
DROP TABLE 테이블명
- 테이블 변경
- 컬럼추가
ALTER TABLE 테이블명 ADD (컬럼명 데이터타입(크기) [DEFAULT 기본값]);
- 컬럼수정
ALTER TABLE 테이블명 MODIFY (컬럼명 테이터타입(크기) [DEFAULT 기본값]);
- 컬럼삭제
ALTER TABLE 테이블명 DROP 컬럼명;
- 테이블 이름 변경
RENAME 테이블명 TO 새테이블명
- 테이블 절단하기
TRUNCATE TABLE 테이블명; -- truncate는 테이블에서 모든 행을 제거한다. -- 해당 테이블이 사용하는 저장공간을 해제한다. -- truncate로 제거된 행은 rollback할 수 없다.
시퀀스
- 일련번호를 자동으로 생성하는 데이터베이스 객체다.
- 기본키 값(행을 대표하는 값)을 생성하는데 주로 사용됩니다.
- 시퀀스 생성
CREATE SEQUENCE 시퀀스명;
-- 1부터 1씩 증가하는 번호가 발행된다.
CREATE SEQUENCE 시퀀스명
[INCREMENT BY a] a씩 증가한다.
[START WITH b] b부터 시작한다.
[{MAXVALUE c | NOMAXVALUE}] c가 최대값이다.
[{MINVALUE d | NOMINVALUE}] d가 최소값이다.
[{CYCLE | NOCYCLE}] 최대값/최소값이 도달했을 때 반복여부를 결정한다.
[{CACHE e | NOCACHE}] 일련번호를 e개 만큼 미리 할당해서 메모리에 캐시하거나, 캐시를 활용하지 않는다.
- 시퀀스 생성하기 예제
CREATE SEQUENCE 시퀀스명
INCREMENT BY 1
START WITH 1
NOMAXVALUE
NOMINVALUE
NOCYCLE
CACHE 20;
- 시퀀스의 삭제
DROP SEQUENCE 시퀀스명
- 시퀀스의 수정
ALTER SEQUENCE 시퀀스명
[INCREMENT BY a]
[{MAXVALUE c | NOMAXVALUE}]
[{MINVALUE d | NOMINVALUE}]
[{CYCLE | NOCYCLE}]
[{CACHE e | NOCACHE}]
-- START WITH를 제외한 나머지 설정을 변경할 수 있다.
- 시퀀스의 사용
- 시퀀스명.NEXTVAL
- 새로운 일련번호를 반환한다.
- 시퀀스명.CURRVAL
- 현재 연결된 세션에서 nextval를 통해서 발행했던 번호를 다시 .
- CURRVAL을 사용하려면 해당 시퀀스에 대한 NEXTVAL이 실행된 후에만 가능한다.
- 시퀀스명.NEXTVAL
뷰
- 테이블 혹은 다른 뷰를 기반으로 하는 가상의 테이블(논리적인 테이블)이다.
- 특징
- 물리적인 저장공간을 가지지 않는다.
- INSERT, UPDATE, DETELE 작업의 수행이 불편하다.
- 목적
- 복잡한 SQL문을 간단하게 작성하기 위해서 사용
- 데이터의 엑세스를 제한하기 위해서 사용(데이터에 대한 보안성 강화)
- 동일한 데이터로부터 다양한 결과를 얻기 위해서 사용
- 종류
- 단순 뷰
- 한 테이블에서만 데이터를 가져온다.
- 함수 또는 데이터 그룹을 사용하지 않았음
- DML(INSERT/UPDATE/DELETE가 가능은 하다)
- 복합 뷰
- 여러 테이블에 데이터를 가져온다.
- 함수 또는 데이터 그룹을 포함하고 있음
- DML 거의 불가능하다.
- 단순 뷰
- 뷰 생성
CREATE [OR REPLACE] VIEW 뷰이름
AS 서브쿼리
WITH READ ONLY
-- 서브쿼리는 가상의 테이블이 포함할 데이터를 조회하는 SELECT문
- 뷰 수정
CREATE OR REPLACE VIEW 뷰이름
AS 서브쿼리
-- 뷰이름을 수정하려는 기존 뷰이름과 동일하게 지정하면 된다.
- 뷰 삭제
DROP VIEW 뷰이름
인라인 뷰
- SELECT 문의 FROM절에 서브쿼리를 정의하고, 이 서브쿼리로 조회된 결과를 가상의 테이블로 취급하고, 별칭을 부여한 것
- 데이터베이스 객체가 아니다.
- 형식
SELECT A.column, A.column, A.column
FROM (SELECT column, column, column, ...
FROM table1
WHERE 조건식) A
WHERE 조건식
인덱스(색인)
- 데이터 행의 검색 속도를 향상시키기 위해서 사용되는 데이터베이스 객체다.
- 데이터의 위치를 빠르게 찾는 신속한 경로 엑세스 방법을 사용하여 디스크 I/O를 줄여 준다.
- 인덱스는 테이블과 독립적으로 존재한다.
- 한 번 생성된 인덱스는 Oracle이 자동으로 유지 관리한다.
- 테이블이 삭제되면 그 테이블의 데이터를 색인화하고 있는 인덱스도 같이 삭제된다.
- 인덱스 생성
- 자동 생성
- 테이블 정의할 때 primary key 제약조건, unique 제약조건이 정의된 컬럼의 값들은 자동으로 인덱스가 생성된다.
- 수동 생성
- 사용자가 행에 대한 엑세스 시간을 줄이기 위해서 특정 열을 대상으로 인덱스를 생성할 수 있다.
- 자동 생성
- 인덱스 생성하기
CREATE INDEX 인덱스명
ON 테이블명 (컬럼명, ....)
- 인덱스 삭제하기
DROP INDEX 인덱스명
- 함수 기반 인덱스 생성하기
CREATE INDEX 인덱스명
ON 테이블명 (오라클함수)
- 인덱스를 생성이 필요한 경우
- where절이나 조인조건에 자주 사용되는 경우
- 컬럼이 매우 다양한 값을 포함하고 있는 경우
- 데이터가 아주 많은 테이블을 대상으로 조회작업을 했을 때 대부분의 조회작업에서 검색되는 행이 전체 데이터의 2%~4%미만인 경우
- 인덱스 생성이 필요하지 않는 경우
- 테이블이 작은 경우
- 테이블이 자주 갱신되는 경우
- 인덱스화된 열이 표현식의 일부로 사용되는 경우
- where절의 조회 조건으로 자주 사용되지 않는 경우
- 대부분의 조회작업에서 전체 데이터의 2%~4%이상 검색되는 경우
트리거
- 특정 테이블에 INSERT, UPDATE, DELETE 작업이 수행될 때 자동으로 실행되는 것이다.
- 트리거는 데이터베이스 객체다.
- 종류
- 행 트리거
- 테이블의 데이터가 변경될 때 실행되는 트리거
- 문장 트리거
- 영향을 받는 행이 없더라고 실행되는 트리거
- 특정 시간에 실행되는 트리거
- 행 트리거
- 형식
CREATE OR REPLACE TRIGGER 트리거명
{BEFORE | AFTER} -- 트리거 실행 싯점
{INSERT, UPDATE, DELETE} ON 테이블명 -- 이벤트종류
FOR EACH ROW -- 데이터 행의 변화가 생길 때 마다 실행된다
BEGIN
실행할 SQL
END;
-
트리거의 접두어(OLD, NEW)
- OLD, NEW 접두어는 행 트리거에서만 사용가능하다.
- 트리거 수행문에서 변경이 발생한 행의 이전값, 변경된(추가된 값)을 사용할 수 있다.
작업 OLD값 NEW값 INSERT NULL 추가된 값 UPDATE 갱신전의 값 갱신후의 값 DELETE 삭제전의 값 NULL
- 작성예
- 주문정보 이력 저장하기
- 주문정보가 추가되거나, 주문상태가 변경될 때마다 그 이력을 저장하기
- 주문정보 이력을 저장하는 테이블 생성하기
create table tb_order_history ( order_no number(7), cust_no number(5), order_status varchar2(20), order_update_date date );
- 주문정보 추가/변경시 실행될 트리거 생성하기
CREATE OR REPLACE TRIGGER order_history_trigger AFTER INSERT OR UPDATE ON tb_orders FOR EACH ROW BEGIN insert into tb_order_history (order_no, cust_no, order_status, order_update_date) values (:new.order_no, :new.cust_no, :new.order_status, sysdate); END;
- 주문정보 이력 저장하기
- 트리거 활성화 비활성화 하기
ALTER TRIGGER 트리거명 ENABLE;
ALTER TRIGGER 트리거명 DISABLE;
- 트리거 삭제하기
DROP TRIGGER 트리거명;
-- 테이블에 저장된 각 행들의 ROWID 조회하기
SELECT ROWID, department_id, department_name
FROM departments;
select rowid, department_id, department_name
from departments;
-- 1부터 시작하는 시퀀스 생성하기
CREATE SEQUENCE product_seq
START WITH 1
NOCACHE;
SELECT product_seq.NEXTVAL FROM dual;
-- 상품테이블 생성하기
CREATE TABLE sample_products (
product_no number(8) primary key,
product_name varchar2(200) not null,
product_maker varchar2(100) not null,
product_category varchar2(100) not null,
product_price number(8) not null,
product_discount_price number(8) not null,
product_stock number(5) default 100,
product_sold_out char(1) default 'N',
product_created_date date default sysdate
);
-- 상품테이블에 상품정보 저장하기
INSERT INTO sample_products
(product_no, product_name, product_maker, product_category, product_price, product_discount_price)
values (product_seq.nextval, 'iphone12 plus', 'apple', '스마트폰', 1400000, 1200000);
-- 새로운 일련번호 조회하기
SELECT PRODUCT_SEQ.nextval FROM dual;
-- 현재 시퀀스의 일련번호 조회하기
SELECT product_seq.currval FROM dual;
------------- 퀴즈
-- 사원아이디, 이름, 소속부서 아이디, 소속부서명을 조회하기
SELECT e.employee_id, e.first_name, d.department_id, d.department_name
FROM employees E, departments D;
-- 60번부서에 소속된 사원들의 사원아이디, 이름, 급여, 직종아이디, 직종제목, 직종최저급여, 직종최고급여를 조회하기
SELECT e.employee_id, e.first_name, e.salary, j.job_id, j.job_title, j.min_salary, j.max_salary
FROM employees E, jobs J
WHERE e.department_id = 60
AND e.job_id = j.job_id;
-- 모든 사원들의 사원아이디, 이름, 급여, 급여등급을 조회하기
SELECT e.employee_id, e.first_name, e.salary, s.grade
FROM employees E, salary_grade S
WHERE e.salary >= s.min_salary and e.salary <= s.max_salary
ORDER BY e.employee_id;
-- 60번부서에 소속된 사원들의 사원아이디, 이름, 상사의 이름을 조회하기
SELECT e.employee_id, e.first_name, m.first_name
FROM employees E, employees M
WHERE e.employee_id = m.manager_id
AND e.department_id = 60;
-- 부서관리자가 있는 부서의 부서아이디, 부서명, 부서관리자 아이디, 부서관리자이름을 조회하기
SELECT d.department_id, d.department_name, d.manager_id, e.first_name
FROM departments D, employees E
WHERE d.department_id = e.department_id
AND d.manager_id = e.employee_id
AND d.manager_id is not null;
-- 부서관리자가 있는 부서의 부서소재지 도시명을 중복없이 조회하기
SELECT DISTINCT l.city
FROM departments D, locations L
WHERE d.manager_id is not null
AND d.location_id = l.location_id;
-- 소속부서명이 'Sales'이고, 급여등급이 'A'나 'B'에 해당하는 사원들의 아이디, 이름, 급여, 급여등급을 조회하기
SELECT e.employee_id, e.first_name, e.salary, s.grade
FROM employees E, departments D, salary_grade S
WHERE e.department_id = d.department_id
AND d.department_name = 'Sales'
AND e.salary >= s.min_salary and e.salary <= s.max_salary
AND s.grade in ('A', 'B');
-- 60번 부서에 소속된 사원들의 평균급여를 조회하기
SELECT AVG(salary)
FROM employees
WHERE department_id = 60;
-- 직종아이디별 사원수를 조회하기
SELECT job_id, COUNT(*)
FROM employees
GROUP BY job_id;
-- 급여 등급별 사원수를 조회하기
SELECT s.grade, COUNT(*)
FROM employees E, salary_grade S
WHERE e.salary >= s.min_salary AND e.salary < s.max_salary
GROUP BY s.grade;
-- 2007년 입사한 사원들의 월별 입사자 수를 조회하기
SELECT to_char(hire_date, 'MM') MM, COUNT(*)
FROM employees
WHERE hire_date >= to_date('2007/01/01') and hire_date < to_date('2008/01/01')
GROUP BY to_char(hire_date, 'MM')
ORDER BY to_char(hire_date, 'MM');
Author And Source
이 문제에 관하여(2021. 05. 06(목) TIL), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@eastgun_/2021.-05.-06목-TIL저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)