데이터베이스의 '외래키'(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;






+ Recent posts