Sub Query는 쿼리 안의 쿼리라고 이해하면 쉬울수도 있다.


일반적으로 Select ~ From ~;과 같이 쓰는데


서브 쿼리는 Select ~ From (Select ~ From ~);


위와 같이 쿼리 안에 쿼리는 넣는다




특정 테이블에서 뽑은 데이터를


다시한번 검색하는것이다.


보통 테이블을 2개 이상 사용할 때나 key값이 연관이 있을 때 사용한다.


예를 보면 좀 더 쉽게 이해될것이다.



-- 테이스를 위한 테이블 생성

-- 직원 테이블 생성
CREATE TABLE emp(
    ename VARCHAR2(20),
    job VARCHAR2(50),
    deptno VARCHAR2(10),
    hiredate DATE
);

-- 부서 테이블 생성
CREATE TABLE dept(
    deptno VARCHAR2(10),
    deptname VARCHAR2(20),
    loc VARCHAR2(10)
);

-- 테스트를 위한 데이터 삽입
INSERT INTO emp VALUES('lee', 'staff', 1, to_date('15/01/02', 'YY/MM/DD'));
INSERT INTO emp VALUES('kim', 'staff', 1, to_date('15/03/06', 'YY/MM/DD'));
INSERT INTO emp VALUES('jun', 'assistant', 2, to_date('15/05/15', 'YY/MM/DD'));
INSERT INTO emp VALUES('chu', 'staff', 1, to_date('15/07/08', 'YY/MM/DD'));
INSERT INTO emp VALUES('sin', 'manager', 2, to_date('15/10/28', 'YY/MM/DD'));
INSERT INTO emp VALUES('jin', 'assistant', 1, to_date('15/12/25', 'YY/MM/DD'));
INSERT INTO emp VALUES('son', 'staff', 2, to_date('16/01/13', 'YY/MM/DD'));
INSERT INTO emp VALUES('han', 'staff', 3, to_date('16/04/06', 'YY/MM/DD'));
INSERT INTO emp VALUES('hyun', 'leader', 4, to_date('16/08/15', 'YY/MM/DD'));
INSERT INTO emp VALUES('ma', 'manager', 4, to_date('16/11/11', 'YY/MM/DD'));

INSERT INTO dept VALUES(1, 'sales', 'NEWYORK');
INSERT INTO dept VALUES(2, 'dev01', 'LA');
INSERT INTO dept VALUES(3, 'personal', 'NEWYORK');
INSERT INTO dept VALUES(4, 'delevery', 'BOSTON');

SELECT * FROM emp;
SELECT * FROM dept;

-- deptno가 pk, fk가 된다.

-- 문제 1) han의 근무 부서를 찾아라
-- 1단계 - 결과 3
SELECT deptno FROM emp WHERE ename = 'han';
-- 2단계 - 결과 찾기
SELECT deptname FROM dept WHERE deptno = 3;
-- 3단계 - 합치기
SELECT deptname FROM dept WHERE (SELECT deptno FROM emp WHERE ename = 'han') = deptno;


-- 문제 2) 위치가 LA나 BOSTON인 부서에 속한 사람들의 이름과 직책
-- 1단계(in이 마음에 안들면 or을 쓰자
SELECT deptno FROM dept WHERE loc IN('LA', 'BOSTON');
-- 2단계
SELECT ename, job FROM emp WHERE deptno IN(2,4);
-- 3단계
SELECT ename, job FROM emp WHERE deptno IN(SELECT deptno FROM dept WHERE loc IN('LA', 'BOSTON'));
-- 비교 연산자
-- IN       : 메인 쿼리와 비교 조건이 서브 쿼리의 결과 중 하나라도 일치하면, OR와 비슷 (비교만 가능)
-- ALL      : 메인 쿼리와 비교 조건이 서브 쿼리의 결과 중 모두 일치하면, AND와 비슷
-- EXISTS   : 메인 쿼리와 비교 조건이 서브 쿼리의 결과 중 값이 하나라도 있으면, OR와 비슷 (작다, 크다 등 가능)


-- 문제 3) 직책이 MANAGER인 사원들 중 가장 입사일이 빠른 사원보다 입사일이 빠른 직원의 데이터
-- 1단계
SELECT MIN(hiredate) FROM emp WHERE job = 'manager';
-- 2단계
SELECT ename, job FROM emp WHERE hiredate < '15/10/28';
-- 3단계
SELECT ename, job FROM emp WHERE hiredate < (SELECT MIN(hiredate) FROM emp WHERE job = 'manager');


-- 문제 4) sales 부서에서 일하는 사원 정보 추출(이름, 직책, 입사일)
-- 1단계
SELECT deptno FROM dept WHERE deptname = 'sales';
-- 2단계
SELECT ename, job, hiredate FROM emp WHERE deptno = 1;
-- 3단계
SELECT ename, job, hiredate FROM emp WHERE deptno = (SELECT deptno FROM dept WHERE deptname = 'sales');



-- 문제 5) 부서별로 직원이 몇명인지 확인
-- 추출한 값을 하나의 컬럼처럼 보여주는 것 -> 상하관계 쿼리
SELECT deptname, loc, (SELECT COUNT(*) FROM emp WHERE emp.deptno = dept.deptno) AS cnt FROM dept;
-- dept d, dept AS d 와 같이 식별자를 지정하여 사용할 수 있음
SELECT deptname, loc, (SELECT COUNT(*) FROM emp WHERE emp.deptno = d.deptno) AS cnt FROM dept d;







데이터베이스의 '외래키'(Foreign Key)는


어떤 테이블에서 다른 테이블의 기본키를 참조하는 키를 말한다.


예를들어


학생 테이블이 있고 국어 과목의 학생 테이블이 있다면


학생 테이블에는 (학번, 이름, 이메일 등), 학번이 기본키


국어 테이블에는 (학번, 출석번호, 중간점수, 기말점수 등) 학번이 외래키, 출석번호가 기본키


위와 같이 국어테이블이 학생 테이블의 학번을 참조하여 사용하는 것이다.




여기서 학생 테이블의 경우는 키를 빌려주기 때문에 부모 테이블이라고 하고


국어 테이블은 빌려와 쓰기 때문에 자식 테이블이라고 한다.



-- 1. 참조 제약 조건 (FOREIGN KEY () REFERENCES)
-- FOREIGN KEY(외래키) FK
-- 외부에서 부터 가져온 키
-- 부모 테이블
CREATE TABLE parentTable(
    userId VARCHAR2(30),
    userName VARCHAR2(20),
    userPhone VARCHAR2(13),
    userAddr VARCHAR2(100),
    CONSTRAINT parent_pk PRIMARY KEY(userId)
);

-- 자식 테이블(외래키)
CREATE TABLE childTable(
    orderId NUMBER(10),
    userId VARCHAR2(30),
    productName VARCHAR2(20),
    price NUMBER(10),
    qty NUMBER(5)
--  CONSTRAINT fk_child FOREIGN KEY(userId)
--  REFERENCES parentTable(userId)
);

-- 외래키 추가(비식별 관계 : 부모의 pk를 일반 필드로 사용)
ALTER TABLE childTable ADD CONSTRAINT fk_child FOREIGN KEY(userId) REFERENCES parentTable(userId);

-- 외래키 추가(식별 관계 : 부모의 pk를 자식의 pk로 사용)
-- 이름이 fk_child와 같이 지정하는 형식이 아니므로 임의로 지정됨
CREATE TABLE idenTable(
    userId VARCHAR2(30),
    PRIMARY KEY(userId),
    FOREIGN KEY(userId) REFERENCES parentTable(userId)
);

-- 식별 관계 - 기본키로 사용 하냐 안하냐


-- Unique 제약 조건 (UNIQUE)
-- 중복을 허용 하지 않는다.
-- NULL을 허용 된다.
-- 테이블에 여러개가 존재 할 수 있음.
ALTER TABLE childTable ADD CONSTRAINT pd_name_uq UNIQUE(productName);

-- 해당 테이블의 제약 조건 검색
SELECT constraint_name, table_name FROM USER_CONSTRAINTS;
-- parent 테이블이랑 child 테이블의 제약조건만 검색
SELECT constraint_name, table_name FROM USER_CONSTRAINTS WHERE table_name = 'CHILDTABLE' OR table_name = 'PARENTTABLE';



-- 연계 참조 무결성 제약조건 (ON DELETE CASCADE)
-- 무결성 : 논리적으로 앞, 뒤가 맞는가?
-- 부모 자식간의 논리적 관계를 의미
-- 부모키에서 값이 사라지면, 참조하는 자식의 값도 사라지는 제약조건
-- ex) 게시글의 댓글이 15개 있다. 게시글이 삭제 된다면 그의 자식인 댓글도 함께 삭제된다.

-- 부모 테이블
CREATE TABLE supplier(
    supplier_id NUMBER(10),
    supplier_name NVARCHAR2(20) NOT NULL,
    phone VARCHAR2(13),
    CONSTRAINT pk_supplier_id PRIMARY KEY(supplier_id)
);
-- 자식 테이블
CREATE TABLE products(
    product_id NUMBER(10),
    supplier_id NUMBER(10),
    product_price NUMBER(10),
    CONSTRAINT fk_supplier_id FOREIGN KEY (supplier_id) REFERENCES supplier(supplier_id) ON DELETE CASCADE
);

-- 자료 넣고 시험해보기
-- 부모테이블 데이터 추가
INSERT INTO supplier VALUES(1, '김철수', '010-1234-1234');
INSERT INTO supplier VALUES(2, '홍길동', '032-4321-1234');
INSERT INTO supplier VALUES(3, '박영수', '011-1212-3434');
SELECT * FROM supplier;

--자식 테이블 데이터 추가
INSERT INTO products VALUES(1111, 1, 6000);
INSERT INTO products VALUES(1112, 2, 7000);
INSERT INTO products VALUES(1113, 3, 8000);
INSERT INTO products VALUES(1114, 1, 7000);
SELECT * FROM products;

-- 부모 테이블의 항목을 지운다.
DELETE FROM supplier WHERE supplier_id = 1;
SELECT * FROM supplier;
SELECT * FROM products;

-- ORA-02449 오류 : 외래키에 의해 참조된 테이블의 유니크/기본키가 존재합니다.
DROP TABLE supplier;

-- 해결법1 - 자식 테이블을 모두 지우고 부모 테이블을 지운다.

-- 해결법2 - 테이블과 함께 CASCADE 제약 조건을 삭제 한다.
DROP TABLE supplier CASCADE CONSTRAINTS;
-- 이 후 자식 테이블은 제약 없이 삭제 할 수 있다.


-- Check 제약 조건
-- 예전에 쓰던 기능으로 DB쪽의 부담을 줄이기 위해 잘 안쓴다.
-- DB쪽에서 계산을 돌리는것은 비효율적
-- products 입력시 product_price가 5,000~10,000 사이의 값만 받게 한다.
ALTER TABLE products ADD CONSTRAINT chk_price CHECK(product_price BETWEEN 5000 AND 10000);

SELECT * FROM products;

INSERT INTO products VALUES(1114, 2, 6000);
-- 오류 발생 ORA-02290: check constraint (WEB_USER.CHK_PRICE) violated
INSERT INTO products VALUES(1115, 3, 15000);

-- CHECK 제약조건 주의사항
-- 기존에 입력된 값은 CHECK 제약 조건에 영향을 받지 않는다.
-- => 즉, 기존 데이터는 CHECK 제약 조건에 걸리지 않고 유지

-- 확인
SELECT * FROM USER_CONSTRAINTS WHERE table_name = 'PRODUCTS';







25번째 줄까지 코드를 실행하면 위와같이 테이블 모델이 연결된다.

제약조건을 먼저 보기전에


데이터베이스는 '기본키'라는 개념이 있다.


예를들어 학생부 리스트가 쭉 있을 때 다른 항목과 중복이 없어 항상 구분이 되는 항목이 있을것이다.


학번과 같은 항목 말이다.


기본키는 중복이 없고 무조건 값이 들어가야 하고 데이터 베이스 상 한개의 항목만 지정할 수 있다.


영어로는 Primary Key라고 한다.




-- 제약 조건은 추가 삭제만 가능하다.
-- 기본키(primary key) - 중복X, NOT NULL
-- 1) 테이블 생성 시 1(오라클 방식)
CREATE TABLE pkTestName (
    firstCol NCHAR(8) NOT NULL,
    secondCol NVARCHAR2(4),
    CONSTRAINT pk_code PRIMARY KEY(secondCol)
);
-- CONSTRAINT를 통해서 기본키가 무엇인지 지정
desc pkTestName;

-- 2) 테이블 생성 시 2(다른 DB 프로그램 방식)
CREATE TABLE pkTest(
    firstCol NUMBER(3) PRIMARY KEY,
    secondCol NVARCHAR2(4)
);

-- 3) 완성된 테이블에 PK를 지정할 경우
-- ALTER TABLE [table] ADD CONSTRAINT [이름] [제약조건] (필드)
ALTER TABLE employees ADD CONSTRAINT pk_emp_no PRIMARY KEY (emp_no);


-- 기본키는 테이블당 1개만 존재
-- 하지만 여러개의 컬럼을 합쳐서 지정하는것을 복합키라고 함, 추천하는 방식은 아님
-- 주민번호의 앞자리 + 뒷자리처럼
-- 최대 16개의 컬럼에 가능
CREATE TABLE pkTwoTest(
    firstCol NUMBER(5),
    secondCol NUMBER(5),
    thirdCol DATE,
    CONSTRAINT pk_two PRIMARY KEY(firstCol, secondCol)
);

-- NOT NULL을 완성된 테이블에 추가
-- NOT NULL은 key와 다르게 속성으로 취급
-- 기존 테이블 속성 바꾸는 방법과 동일
ALTER TABLE pkTwoTest MODIFY thirdCol VARCHAR2(4) NOT NULL;
DESC pkTwoTest;


-- 제약조건 확인
SELECT constraint_name, table_name FROM USER_CONSTRAINTS;
-- 위와 같이 특수한 정보가 저장되는 테이블을 오라클에서 자동적으로 관리함.

-- 제약조건 삭제
ALTER TABLE pkTestName DROP CONSTRAINT SYS_C006997;

-- Primary Key는 매우 중요한 키로 중복되는 항목을 차단하기 때문에 왠만하면 사용하는것을 추천.











27줄의 복합키 생성 부분을 실행하고 찍은 스크린샷인데


키가 잘 지정됫는지 확인할 때 좌측의 접속 리스트의 상단에 새로고침 버튼을 누르고


접속한 계정, WEB_USER의 테이블 리스트를 펼치고 만든 테이블을 누르면 화면에 보이게 된다.


그 중 모델에서 확인할 수 있다.









먼저 data.sql 파일을 받아서 Insert 문을 실행하여 데이터를 추가하자


data.sql


만약 글자가 깨져 보인다면 https://qdgbjsdnb.tistory.com/100 UTF-8 설정을 참조하자.


다운로드가 귀찮다면 아래 코드를 복사하여 실행



INSERT INTO employees(EMP_NO,FIRST_NAME,FAMILY_NAME,EMAIL,MOBILE,SALARY,DEPART_NO,COMMISION)
VALUES(117,'상민','전','sky05clzls@naver.com','01012341234',4563989,'DEV_003',90);

INSERT INTO employees(EMP_NO,FIRST_NAME,FAMILY_NAME,EMAIL,MOBILE,SALARY,DEPART_NO,COMMISION)
VALUES(119,'항오','조','sky07clzls@naver.com','01012341234',4562752,'DEV_003',90);

INSERT INTO employees(EMP_NO,FIRST_NAME,FAMILY_NAME,EMAIL,MOBILE,SALARY,DEPART_NO,COMMISION)
VALUES(120,'지훈','김','sky08clzls@naver.com','01012341234',56376,'DEV_003',90);

INSERT INTO employees(EMP_NO,FIRST_NAME,FAMILY_NAME,EMAIL,MOBILE,SALARY,DEPART_NO,COMMISION)
VALUES(121,'형진','박','sky09clzls@naver.com','01012341234',56780,'DEV_004',90);

INSERT INTO employees(EMP_NO,FIRST_NAME,FAMILY_NAME,EMAIL,MOBILE,SALARY,DEPART_NO,COMMISION)
VALUES(122,'덕기','이','sky10clzls@naver.com','01012341234',893530,'DEV_004',90);

INSERT INTO employees(EMP_NO,FIRST_NAME,FAMILY_NAME,EMAIL,MOBILE,SALARY,DEPART_NO,COMMISION)
VALUES(123,'혁준','권','sky11clzls@naver.com','01012341234',63543640,'DEV_004',90);

INSERT INTO employees(EMP_NO,FIRST_NAME,FAMILY_NAME,EMAIL,MOBILE,SALARY,DEPART_NO,COMMISION)
VALUES(124,'기빈','고','sky12clzls@naver.com','01012341234',4453830,'DEV_004',90);

INSERT INTO employees(EMP_NO,FIRST_NAME,FAMILY_NAME,EMAIL,MOBILE,SALARY,DEPART_NO,COMMISION)
VALUES(125,'강인','최','sky13clzls@naver.com','01012341234',3786534,'DEV_005',90);

INSERT INTO employees(EMP_NO,FIRST_NAME,FAMILY_NAME,EMAIL,MOBILE,SALARY,DEPART_NO,COMMISION)
VALUES(126,'두원','김','sky14clzls@naver.com','01012341234',876547,'DEV_005',90);

INSERT INTO employees(EMP_NO,FIRST_NAME,FAMILY_NAME,EMAIL,MOBILE,SALARY,DEPART_NO,COMMISION)
VALUES(127,'상헌','류','sky15clzls@naver.com','01012341234',135468,'DEV_005',90);


불러오고 나서 우측 위의 콤보박스를 눌러 WEB_USER를 접속 설정해준 다음


전부 드래그 하여 ctrl + Enter를 누르거나


F5를 눌러 실행하면 데이터가 추가된다.






트랜잭션은 data base 에서 사용되는 쪼갤 수 없는 업무처리의 단위이다.


작업 과정 중 하나라도 잘못된다면 전부 취소해야 한다.




간단하게 예를든다면


A가 B에게 송금을 한다면


A가 은행에게 돈을 전달하고 (트랜잭션 하나)


은행이 B에게 돈을 전달한다.(트랜잭션 하나)


만약 은행에서 B에게 전달하는 과정에 오류가 발생한다면


A의 돈은 이미 깎인 상태이므로 A가 은행에게 전달한 돈까지 취소해주어야 한다. (RoLL Back)




이와 같이 트랜잭션 원리는 금융, 결제와 같은 분야에서 적용된다.




SAVE POINT


DB에서는 게임과 똑같이 SAVE POINT를 지정할 수 있다.


그리고 작업하다가 원하는 부분으로 되돌릴 수 있다.


하지만 세이브 포인트를 잘못쓰면 데이터가 꼬일 수 도 있다.


사용에는 많은 경험이 요구된다.


특히 다수의 개발자가 투입되면 어느 부분이 중요한지 생각이 다 다르고 SAVE POINT를 주는 부분도 다르게 되므로


조심해야 하는 것이다.

-- 1) COMMIT : 실행한 쿼리를 최종 적용(INSERT문, UPDATE문, DELETE문 등...)
-- COMMIT 모드가 켜져있는지 꺼져있는지 알려줌
SHOW AUTOCOMMIT;
-- 쿼리 실행 즉시 COMMIT(비추천)이 된다.
SET AUTOCOMMIT ON;

SET AUTOCOMMIT OFF;

-- COMMIT이 원래 자동으로 되는 구문들
-- CREATE문, ALTER문, DROP문, TRUNCATE문, RENAME문
-- 위의 문구를 사용할 때에는 주의해야 한다.





-- 2) ROLLBACK : 실행한 쿼리(INSERT문, UPDATE문, DELETE문 등...)를 취소(원상 복구)
SELECT * FROM employees;
DELETE FROM employees;
SELECT * FROM employees;

ROLLBACK;
SELECT * FROM employees;
-- ROLLBACK은 시간이 지나면 안됨, 시간이 지나면 자동으로 COMMIT이 됨
-- DELETE문을 조건없이 저런식으로 잘못 사용하면 모든 데이터가 날아감
-- 회사에서 쫓겨나기 딱 좋다.

-- COMMIT을 하지 않으면 원격지의 사용자는 적용 내용 확인 불가
-- 원격지는 다른곳에서 DB를 읽는 경우
-- 그래서 중요한 구문의 경우는 바로 COMMIT을 해 준다.

-- SAVE POINT는 롤백 지점을 원하는 부분에 지정
DELETE FROM employees WHERE emp_no BETWEEN 111 AND 113;
-- 순서상으로 111~113이 지워진 이 후 SAVE가 되었다.
SAVEPOINT pointA;


DELETE FROM employees WHERE emp_no BETWEEN 114 AND 116;
-- 순서상으로 114~116이 지워진 이 후 SAVE가 되었다.
SAVEPOINT pointB;

SELECT * FROM employees ORDER BY emp_no;

-- 4) ROLLBACK TO [point name]
ROLLBACK TO pointA;
-- 111~113이 지워진 후 저장된 시점으로 돌아옴
SELECT * FROM employees ORDER BY emp_no;






DML은 데이터 조작 언어로 데이터를 검색, 등록 삭제, 갱신을 위한 언어이다.


단순하게 만든 테이블과 컬럼안의 데이터들을 다루는 언어이다.


컬럼을 만들었으므로 삽입부터 쭉 다룬다.


이 중 Merge는 조건이 맞을경우, 틀릴경우 작동하는데


jsp같은데서 사용할 때 조건문을 사용하지 db에서는 잘 쓰지 않는다.


이런게 있구나 하고 넘어가면 된다.




Insert, Update, Delete, Merge


-- DML은 테이블의 데이터를 입력/수정/삭제/읽기를 다룬다.
-- 
-- 1. 데이터 추가
-- INSERT INTO [테이블 명] ([컬럼 명], ...) VALUES ([넣을 값], ...);
DESC employees;

INSERT INTO employees (emp_no, first_name, family_name, email,
                        mobile, salary, commision)
        VALUES (111, '둘리', '고', 'asd@acomp.com', '01234567890', 10000000, 90);
INSERT INTO employees (emp_no, first_name, family_name, email,
                        mobile, salary, commision)
        VALUES (112, '또치', '고', 'asd@acomp.com', '01234567890', 10000000, 90);
INSERT INTO employees (emp_no, first_name, family_name, email,
                        mobile, salary, depart_no, commision)
        VALUES (113, '도넛', '고', 'asd@acomp.com', '01234567890', 10000000, 3, 90);

SELECT * FROM employees;

-- INSET INTO employees VALUES ( 모든 데이터 값 );와 같이 모든 값이 들어 갈 경우 컬럼명을 생략해도 된다.
-- 하지만 다른 사람이 읽을 때는 컬럼명을 생략했을때 알아보기 힘들어지므로 다 적는것을 추천
-- 현재 예제는 REG_DATE가 중간에 있어서 생략 할 시 오류가 발생, 마지막에 있다면 정상 작동 할 것.

-- 2. 데이터 수정
-- UPDATE [테이블] SET [컬럼] = [변경할 값] WHERE [조건]; 조건을 안붙이면 전부 수정해버리므로 주의!
UPDATE employees SET depart_no = 'DEV_002' WHERE depart_no IS NULL;

SELECT * FROM employees;

-- 커미션이 90인 사람을 10으로
UPDATE employees SET commision = 10 WHERE commision = 90;
-- 이름이 '김지훈'인 사람의 comission을 90으로
UPDATE employees SET commision = 90 WHERE first_name = '또치';

SELECT * FROM employees;

-- 3. 삭제
-- DELETE FROM [테이블] WHERE [조건]; 조건을 안붙이면 전부 지워버리므로 주의!
-- emp_no = 113인 사람 지우기

DELETE FROM employees WHERE emp_no = 113;

SELECT * FROM employees;

-- 삽입
-- emp_no = 113 ~ 117
-- dev_001 1명, 나머지 dev_002
-- commision은 null
INSERT INTO employees (emp_no, first_name, family_name, email,
                        mobile, salary, depart_no)
        VALUES (113, '도넛', '고', 'asd@acomp.com', '01234567890', 10000000, 'DEV_002');
INSERT INTO employees (emp_no, first_name, family_name, email,
                        mobile, salary, depart_no)
        VALUES (114, '길동', '고', 'asd@acomp.com', '01234567890', 10000000, 'DEV_001');
INSERT INTO employees (emp_no, first_name, family_name, email,
                        mobile, salary, depart_no)
        VALUES (115, '희동', '박', 'asd@acomp.com', '01234567890', 10000000, 'DEV_002');
INSERT INTO employees (emp_no, first_name, family_name, email,
                        mobile, salary, depart_no)
        VALUES (116, '이콜', '마', 'asd@acomp.com', '01234567890', 10000000, 'DEV_002');
INSERT INTO employees (emp_no, first_name, family_name, email,
                        mobile, salary, depart_no)
        VALUES (117, '실이', '공', 'asd@acomp.com', '01234567890', 10000000, 'DEV_002');

SELECT * FROM employees;

-- 4. MERGE
-- 특정 조건에 부합하면 수정 또는 삭제 그렇지 않으면 삽입하는 기능
-- MERGE INTO [테이블] USING (서브쿼리) ON (조건);
-- WHEN MATCHED THEN
-- [DELETE] 또는 [UPDATE]
-- WHEN NOT MATCHED THEN
-- [INSERT]
-- 서브 쿼리는 뒤에서 설명하지만 쿼리문으로 뽑아낸 특정 데이터를 쿼리문에서 사용하는 것.
-- 쿼리 안의 쿼리


-- 테이블 하나 사용 시
-- 1) depart_no가 dev_001인 데이터가 있으면 commision을 10으로 변경
-- UPDATE employees SET commision = 10 WHERE depart_no = 'dev_001';
-- DUAL은 가상 테이블로 지금은 텅 비어있음
MERGE INTO employees USING DUAL ON (depart_no = 'DEV_001')
    WHEN MATCHED THEN
        UPDATE SET commision = 10;
-- 여기까지, MATCHED만 사용 할 경우 UPDATE문이나 DELETE문과 다를게 없다.
SELECT * FROM employees;

-- 2) depart_no가 dev_003인 데이터가 있으면 commision을 10으로 변경하고 없으면 추가 한다.
MERGE INTO employees USING DUAL ON (depart_no = 'DEV_003')
    WHEN MATCHED THEN
        UPDATE SET commision = 10
    WHEN NOT MATCHED THEN
        INSERT (emp_no, first_name, family_name, email, mobile, salary, depart_no)
        VALUES (118, '계인', '외', 'E@email.net', '01012345678', 4000000, 'DEV_003');

SELECT * FROM employees;

-- 3) depart_no가 dev_002일 때 commision을 10으로 변경
--    그리고 EMP_NO = 117인 데이터 삭제
MERGE INTO employees USING DUAL ON (depart_no = 'DEV_002')
    WHEN MATCHED THEN
        UPDATE SET commision = 10
        DELETE WHERE emp_no = 117;

SELECT * FROM employees;

-- 테이블 2개 사용 시(스스로)






Select


Select는 데이터 베이스의 항목들을 조회, 읽어오는 것


가장 많이 쓰이고 데이터가 많아질 수록 복잡해진다.


그리고 보통 모든 항목을 표시하는 *을 자주 사용하는데


이는 다른 사람이 봤을때 따로 찾아봐야 하는 일이 생기므로 사용하는걸 권장 x



1. 조회

2. 특정 조건을 만족하는 데이터(WHERE)

3. AND 조건 (A&&B)

4. OR 조건(A||B)

5. BETWEEN AND

6. 중복 제거(DISTINCT)

7. IN

8. IS NULL / IS NOT NULL

9. LIKE

10. 정렬 (ORDER BY)

11. GROUP BY

12. HAVING


-- 1. 데이터 조회
-- 1) 특정 컬럼 조회
-- SELECT [column] FROM [table]
SELECT * FROM employees;
SELECT first_name, family_name, salary FROM employees;

-- 산술 표현(실제 데이터에 적용되지 않음)
SELECT first_name, family_name, salary/10000 FROM employees;

-- 연봉 알아보기(AS를 통해 항목 이름을 임시로 바꿔서 표현)
-- AS는 특정 컬럼에 별칭을 주는 것.
SELECT first_name, family_name, salary / 10000, ((salary/10000) * 12) AS 연봉 FROM employees;

-- 문자열 합치기 (||, 버티컬 바)
SELECT family_name||' ' ||first_name AS 이름, salary / 10000 AS 봉급, ((salary/10000) * 12) AS 연봉 FROM employees;
SELECT family_name||' ' ||first_name AS 이름, salary / 10000 || '만원' AS 봉급, ((salary/10000) * 12) || '만원' AS 연봉 FROM employees;

-- 2)특정 조건을 만족하는 데이터(WHERE)
-- SELECT [column] FROM [table] WHERE [condition];
-- family_name = '고'인 사람을 찾아보자
SELECT family_name||' ' ||first_name AS 이름, salary / 10000 || '만원' AS 봉급, ((salary/10000) * 12) || '만원' AS 연봉 FROM employees WHERE family_name = '고';
-- salary > 5000000
SELECT family_name||' ' ||first_name AS 이름, salary / 10000 || '만원' AS 봉급, ((salary/10000) * 12) || '만원' AS 연봉 FROM employees WHERE salary > 5000000;

-- 3) AND 조건 (A&&B)
-- salary > 3000000, salary <= 7000000
SELECT family_name||' ' ||first_name AS 이름, salary / 10000 || '만원' AS 봉급, ((salary/10000) * 12) || '만원' AS 연봉 FROM employees WHERE salary > 3000000 AND salary < 7000000;

-- 4) OR 조건(A||B)
-- family_name = '고' OR salary > 7000000
SELECT family_name||' ' ||first_name AS 이름, salary / 10000 || '만원' AS 봉급, ((salary/10000) * 12) || '만원' AS 연봉 FROM employees WHERE family_name = '고' OR salary > 7000000;

-- 5) BETWEEN AND
-- WHERE salary >= 3000000 AND salary <= 7000000
-- = WHERE salary BETWEEN 3000000 AND 7000000
-- BETWEEN을 사용하는 이유는 프로그램마다 읽는 방식이 다르기 때문에
-- 예를들어 html에선 <> 비교를 <P> 와 같이 사용하기 때문이다.
SELECT family_name||' ' ||first_name AS 이름, salary / 10000 || '만원' AS 봉급, ((salary/10000) * 12) || '만원' AS 연봉 FROM employees WHERE salary BETWEEN 3000000 AND 7000000;

-- 6) 중복 제거(DISTINCT)
-- SELECT DISTINCT [column] FROM [table];
SELECT DISTINCT salary FROM employees;

-- 7) IN
-- 여러개의 OR 조건을 표현 할 때(속도면에서 우월)
-- 문장이 짧아져 보기쉽고 프로그램 상 속도도 OR보다 빠르다.
SELECT * FROM employees WHERE
family_name = '고' OR family_name = '박' OR family_name = '마';

SELECT * FROM employees WHERE
family_name IN ('고', '박', '마');

-- 8) IS NULL / IS NOT NULL
-- DB에 NULL이 있는건 좋지 않기 때문에 쓸 일이 별로 없을것임.
SELECT * FROM employees WHERE commision IS NULL;
SELECT * FROM employees WHERE commision IS NOT NULL;

-- Like 실험을 위해 수정
UPDATE employees SET email = 'bsd@gmail.com' WHERE first_name = '도넛';
UPDATE employees SET email = 'bsd@gmail.com' WHERE first_name = '길동';
UPDATE employees SET email = 'csd@acomp.com' WHERE first_name = '희동';
UPDATE employees SET email = 'csd@acomp.com' WHERE first_name = '이콜';
-- 9) LIKE
-- 일부 비슷한 내용을 검색
-- WHERE [column] LIKE '[%를 포함한 문자열]'
-- %는 와일드 카드라고 함
-- 앞 자리가 as로 시작하는 ... => as%
-- 뒷 자리가 com으로 끝나는 ... => %com
-- b와 c를 포함하는 ... => %b%c%
SELECT * FROM employees WHERE email LIKE 'as%';
SELECT * FROM employees WHERE email LIKE '%com';
SELECT * FROM employees WHERE email LIKE '%b%c%';

-- gmail 이 포함된 내용을 찾아라
SELECT * FROM employees WHERE email LIKE '%gmail%';

-- 정렬 실험을 위한 UPDATE
UPDATE employees SET salary = 12000000 WHERE first_name = '또치';
UPDATE employees SET salary = 8000000 WHERE first_name = '길동';
UPDATE employees SET salary = 6000000 WHERE first_name = '이콜';
-- 10) 정렬 (ORDER BY)
-- 특정 컬럼을 기준으로 오름차순(ASC) 또는 내림차순 (DESC)
-- SELECT [column] FROM [table] ORDER BY [column] [ASC | DESC]
-- SELECT [column] FROM [table] WHERE [조건] ORDER BY [column] [ASC | DESC]
-- 급여가 높은 사람 순으로 정렬
SELECT * FROM employees ORDER BY salary DESC;
-- 성을 가나다 순으로 정렬
SELECT * FROM employees ORDER BY family_name ASC;
-- ASC, 오름차순은 생략 될 수 있다.
SELECT * FROM employees ORDER BY family_name;
-- 연봉이 높은 사람 기준으로 정렬
-- 별칭을 지정하였을 경우 별칭만 입력해도 됨
SELECT family_name||' ' ||first_name AS 이름, salary / 10000 || '만원' AS 봉급, ((salary/10000) * 12) || '만원' AS 연봉 FROM employees ORDER BY ((salary/10000) * 12) || '만원' ASC;

-- 11) GROUP BY
-- 데이터를 그루핑 하여 가져오는 경우 사용
-- Group by에 사용 할 컬럼은 Select 절의 컬럼에 반드시 있어야 함
-- SUM, AVG와 같은 계산 묶음을 사용하지 않으면 오류 발생, 그룹으로 묶으면 개별 정보를 표현할 수 없기 때문
-- 부서별 급여 합산, 평균
SELECT depart_no, SUM(salary) FROM employees GROUP BY depart_no;
SELECT depart_no, AVG(salary) FROM employees GROUP BY depart_no;
-- 부서별 급여 합과 평균 커미션
SELECT depart_no, SUM(salary), AVG(commision) FROM employees GROUP BY depart_no;


-- 12) HAVING
-- GROUP BY 결과로 부터 특정 조건의 값만 추출
-- HAVING에는 WHERE과 다르게 별칭을 사용할 수 없음.
-- 부서별 급여 합계와 성과급 평균 => 합계가 3000 미만인 그룹만 추출
SELECT depart_no, SUM(salary) as 합, AVG(commision) FROM employees GROUP BY depart_no
HAVING SUM(salary) < 30000000;
-- 부서별 합계가 3000만원 이하인 부서를 금액이 높은 순으로 정렬
SELECT depart_no, SUM(salary) as 합 FROM employees GROUP BY depart_no
HAVING SUM(salary) < 30000000 ORDER BY SUM(salary) DESC;




01-04의 게시물에선


관리자 계정을 이용하여 사용자 계정을 생성하였다.


이번에는 사용자 계정으로 접속하여 테이블을 다뤄본다.



저번에 접속한 SYS계정이 좌측에 보인다.


저번에 생성한 web_user로 접속하는데 생성 당시 비밀번호를 pass로 설정하였으니 그대로 입력하고


테스트를 눌러 확인하고 접속을 누른다.


창이 뜨면 아무거나 입력하고 저번과 같이 저장 경로를 새로 설정한다.




-- 1. 테이블 생성
-- CREATE TABLE [테이블 명] (
-- [컬럼명] [데이터타입] [크기지정]
-- [컬럼명] [데이터타입] [크기지정]
-- [컬럼명] [데이터타입] [크기지정]
-- );
-- 여러개를 집어 넣을 수 있다.

-- 데이터타입 종류 (오라클은 BOOLEAN은 없음)

-- 1) 문자타입(검색속도가 빠르다, DB에선 속도가 중요하지만 DB가 크지 않으므로 지금은 신경쓰지 않아도 된다.)
-- 고정형(사이즈 한번 설정)
-- CHAR(바이트 수) 영어 - 1, 한글 - 2, 한문 - 3 바이트
-- NCHAR(글자 수) 전부 3 바이트 잡아버림

-- 가변형(늘었다 줄었다.), 원래는 VARCHAR와 NVARCHAR였는데 2를 쓰라고 권고
-- VARCHAR2(바이트 수)
-- NVARCHAR2(글자 수)

-- 2) 숫자
-- NUMBER(전체 자릿수, 소숫점 자릿수)
-- NUMBER <-- 오라클이 알아서 계산, 지정해주므로 속도가 느려진다. 그러므로 지정을 하자

-- 3) 날짜
-- Date <-- 7byte(yyyy-mm-dd hh:mm:ss), DEFAULT SYSDATE를 하면 데이터를 입력했을때의 날짜가 입력됨
-- TIMESTAMP <- 10억분의 1초까지 저장
-- yyyy-mm-dd hh:mm:ss.FF9 FF는 소숫점 9번째
-- 타임 스탬프는 누군가가 먼저 등록을 했나, 우열을 가릴 때 사용, 데이터를 조금 더 많이 먹음

CREATE TABLE testtable(
    username NVARCHAR2(10),
    age NUMBER(3, 0),
    mobile NVARCHAR2(11),
    reg_date DATE DEFAULT SYSDATE
);

-- description, 테이블 구조 확인
-- DESC [테이블 명];
DESC testtable;

-- 테이블 리스트 확인
SELECT * FROM USER_TABLES;
SELECT table_name FROM USER_TABLES;

-- 테이블을 아래와 같이 만들어 보자
-- 테이블 명 : employees
-- emp_no 숫자형 3자리
-- first_name 문자열 8자리
-- last_name 문자열 2자
-- email 문자열 50자
-- mobile 문자열 11자
-- salary 숫자형 8자
-- reg_date 날짜 기본으로 SYSDATE 된다.


CREATE TABLE employees(
    emp_no NUMBER(3, 0),
    first_name NVARCHAR2(8),
    last_name NVARCHAR2(2),
    email NVARCHAR2(50),
    mobile NVARCHAR2(11),
    salary NUMBER(8, 0),
    reg_date DATE DEFAULT SYSDATE
);

DESC employees;
-- TABLE을 같은 이름으로 두번 Create 하면 오류가 출력됨
-- 고로 수정하고 싶으면 Drop 했다가 다시 Create하자

-- 2. 테이블 삭제
-- DROP TABLE [테이블 명]
SELECT table_name FROM USER_TABLES;
DROP TABLE testtable;
SELECT table_name FROM USER_TABLES;

-- 테이블 내 데이터 일괄 삭제(추천 하지 않는 기능)
-- DELETE 로 삭제 할 경우 ROLL BACK 가능, 휴지통에 버리기 처럼 남는다.
-- TRUNCATE TABLE [테이블 명]
-- TRUNCATE는 삭제하고 바로 휴지통에 비워버림, 완전 삭제, 복구 불가

-- 3. 테이블 수정(컬럼, 테이블 내부의 항목)

-- 1) 컬럼 이름 변경 - 기존 데이터가 있을 경우 삭제되어 버리므로 주의해야 한다.
-- ALTER TABLE [테이블 명] RENAME COLUMN [어떤 컬럼] TO [바꿀 이름];
ALTER TABLE employees RENAME COLUMN last_name TO family_name;
DESC employees;

-- 2) 컬럼 추가
-- ALTER TABLE [테이블 명] ADD ([컬럼 명] [데이터 타입(크기)]);
ALTER TABLE employees ADD (depart_no VARCHAR2(10));
DESC employees;
ALTER TABLE employees ADD (commision VARCHAR2(10));
ALTER TABLE employees ADD (etc VARCHAR2(100));
DESC employees;

-- 3) 컬럼 속성 변경 - 기존 데이터가 있으면 안된다.
-- ALTER TABLE [테이블 명] MODIFY ([컬럼 명] [데이터 타입(크기)]);
ALTER TABLE employees MODIFY (commision NUMBER(3,0));
DESC employees;

-- 4) 컬럼 삭제
-- ALTER TABLE [테이블 명] DROP COLUMN [컬럼 명];
ALTER TABLE employees DROP COLUMN etc;
DESC employees;




+ Recent posts