mySQL

[mySQL] FOREIGN KEY /삭제 옵션 / IUD

로돌씨 2024. 4. 7. 19:19

FOREIGN KEY / 삭제 옵션

-- FOREIGN KEY
-- 외래키 , 외부키 , 참조키 
-- 다른 테이블의 컬럼값을 참조(REFERENCE)하여 참조하는 테이블의 값만 허용한다.
-- FOREIGN KEY 제약조건을 통해서 다른 테이블과의 관계(RELATIONSHIP)가 형성된다. 

CREATE TABLE USER_GRADE(
	GRADE_CODE INT PRIMARY KEY,
	GRADE_NAME VARCHAR(100) NOT NULL
);

INSERT INTO USER_GRADE VALUES(1,'일반 회원');
INSERT INTO USER_GRADE VALUES(2,'VIP');
INSERT INTO USER_GRADE VALUES(3,'VVIP');
INSERT INTO USER_GRADE VALUES(4,'VVVIP');

SELECT * FROM USER_GRADE;

CREATE TABLE USER_FOREIGN_KEY(
	USER_NO INT PRIMARY KEY,
	USER_ID VARCHAR(20),
	USER_PW VARCHAR(20),
	USER_NAME VARCHAR(15),
	GENDER VARCHAR(1) CHECK(GENDER IN ('M','F')),
	GRADE_CODE INT,
	CONSTRAINT FK_GRADE_CODE FOREIGN KEY(GRADE_CODE) REFERENCES USER_GRA이창DE(GRADE_CODE)
);
INSERT INTO USER_FOREIGN_KEY VALUES(1,'123','321','이길동','F',2);
INSERT INTO USER_FOREIGN_KEY VALUES(2,'1223','3321','이길동','M',4);
INSERT INTO USER_FOREIGN_KEY VALUES(3,'1233','3121','이길동','M',1);
INSERT INTO USER_FOREIGN_KEY VALUES(4,'122133','32321','이길동','F',3);
INSERT INTO USER_FOREIGN_KEY VALUES(5,'12233','32321','이길동','F',1);

-- SQL Error [1452] [23000]: Cannot add or update a child row: a foreign key constraint fails (`multi`.`USER_FOREIGN_KEY`, 
-- 외래키로 지정된 GRADE_CODE는 참조하는 USER_GRADE테이블의 GRADE_CODE에 있는 데이터만 INSERT 가능하다 .
INSERT INTO USER_FOREIGN_KEY VALUES(6,'12D3','3F21','박길동','M',10);

SELECT  * FROM USER_FOREIGN_KEY
JOIN USER_GRADE USING(GRADE_CODE);
->
GRADE_CODE|USER_NO|USER_ID|USER_PW|USER_NAME|GENDER|GRADE_NAME|
----------+-------+-------+-------+---------+------+----------+
         1|      3|1233   |3121   |이길동      |M     |일반 회원    
         1|      5|12233  |32321  |이길동      |F     |일반 회원    
         2|      1|123    |321    |이길동      |F     |VIP       |
         3|      4|122133 |32321  |이길동      |F     |VVIP      |
         4|      2|1223   |3321   |이길동      |M     |VVVIP     |

-- USER_GRADE 테이블에 저장된데이터들중에 GRADE_CODE가 4인 데이터 삭제
-- dml :delete 
-- SQL Error [1451] [23000]: Cannot delete or update a parent row: a foreign key constraint fails (`multi`.`USE
DELETE FROM USER_GRADE
WHERE GRADE_CODE = 4; 

-- 삭제 옵션
-- 일반적으로 참도뇌는 원본 컬럼(user_grade.grade_code)내용을 삭제하려고 할때
-- 외래키로 사용 중인 자식 컬럼(user_foreign_key.grade_code)이 있다면 함부로 삭제 할 수 없다 . 
-- 참조되고있는 원본 테이블의 컬럼값이 삭제 될때 
-- 참조하는 값을 어떻게 처리할것인지 설정하는 옵션 

-- ON DELETE CASCADE : 부모 컬럼 삭제할때 자식도 함께 삭제
-- ON UPDATE CASCADE : 부모 컬럼 업데이트할때 함께 업데이트 

drop table USER_GRADE;
drop table USER_FOREIGN_KEY;


CREATE TABLE USER_FOREIGN_KEY(
	USER_NO INT PRIMARY KEY,
	USER_ID VARCHAR(20),
	USER_PW VARCHAR(20),
	USER_NAME VARCHAR(15),
	GENDER VARCHAR(1) CHECK(GENDER IN ('M','F')),
	GRADE_CODE INT,
	CONSTRAINT FK_GRADE_CODE FOREIGN KEY(GRADE_CODE) 
	REFERENCES USER_GRADE(GRADE_CODE) ON DELETE CASCADE
);
INSERT INTO USER_FOREIGN_KEY VALUES(1,'123','321','이길동','F',2);
INSERT INTO USER_FOREIGN_KEY VALUES(2,'1223','3321','이길동','M',4);
INSERT INTO USER_FOREIGN_KEY VALUES(3,'1233','3121','이길동','M',1);
INSERT INTO USER_FOREIGN_KEY VALUES(4,'122133','32321','이길동','F',3);
INSERT INTO USER_FOREIGN_KEY VALUES(5,'12233','32321','이길동','F',1);

SELECT * FROM USER_GRADE;
SELECT * FROM USER_FOREIGN_KEY;

DELETE FROM USER_GRADE
WHERE GRADE_CODE = 2;

USER_NO|USER_ID|USER_PW|USER_NAME|GENDER|GRADE_CODE|
-------+-------+-------+---------+------+----------+
      2|1223   |3321   |이길동      |M     |         4|
      3|1233   |3121   |이길동      |M     |         1|
      4|122133 |32321  |이길동      |F     |         3|
      5|12233  |32321  |이길동      |F     |         1|
-> 2인데이터가 사라짐 ( 원본에서도 grade 2는 같이 사라졌음)

 

INSERT / UPDATE / DELETE 

-- DML(데이터 조작 언어) --
-- INSERT , UPDATE ,DELETE , SELECT(DQL)
-- [CRUD]
-- C(CREATE)   	: INSERT / 데이터 추가
-- R(READ)		: SELECT / 데이터 조회
-- U(UPDATE)	: UPDATE / 데이터 수정 
-- D(DELETE) 	: DELETE / 데이터 삭제

-- INSERT : 새로운 행을 특정 테이블에 추가하는 명령어 , 
-- 			해당 명령어 실행 후에는 테이블의 행의 개수가 증가.

-- [사용 형식]
-- 1. 특정 컬럼에 값을 추가 
-- INSERT INTO 테이블명(컬럼 , 컬럼 , ...) VALUES(값 , 값 , ...);
-- 2. 모든 컬럼에 값을 추가 
--  	INSERT INTO 테이블명 VALUES(값 , 값 , ...);

desc EMPLOYEE ;
-- 컬럼 명시
INSERT INTO EMPLOYEE (EMP_ID,EMP_NAME,EMP_NO,EMAIL,PHONE,DEPT_CODE,
JOB_CODE,SAL_LEVEL,SALARY,BONUS,MANAGER_ID,HIRE_DATE,ENT_DATE,ENT_YN) 
VALUES(500,'박길동','990307-1213213','dudtjr7137@naver.com','01033351234','D1','J7','S4',3100000,0.1,'200',NOW() ,null , default);

SELECT * from EMPLOYEE where emp_id = 500;

-- 컬럼 생략 
INSERT INTO EMPLOYEE 
VALUES(600 , '박잉석' , '990990-1231233','duddjd@naer.com' , '01033351234','D1','J7','S3' , 4000000,0.2 ,'200',now(), null ,default);


SELECT * from EMPLOYEE where EMP_ID in(500,600);
->
EMP_ID|EMP_NAME|EMP_NO        |EMAIL               |PHONE      |DEPT_CODE|JOB_CODE|SAL_LEVEL|SALARY |BONUS|MANAGER_ID|HIRE_DATE |ENT_DATE|ENT_YN|
------+--------+--------------+--------------------+-----------+---------+--------+---------+-------+-----+----------+----------+--------+------+
500   |박길동     |990307-1213213|dudtjr7137@naver.com|01033351234|D1       |J7      |S4       |3100000|  0.1|200       |2023-03-14|        |N     |
600   |박잉석     |990990-1231233|duddjd@naer.com     |01033351234|D1       |J7      |S3       |4000000|  0.2|200       |2023-03-14|        |N     |

-- insert + subquery
-- INSERT 문에 서브쿼리를 사용하여 values에 작성하던 값 대신 저장하여 추가 가능하다.
create table emp_01(
emp_id int,
emp_name varchar(20),
eopt_title varchar(40)
); 

insert into emp_01(
select emp_id , emp_name , dept_title
from EMPLOYEE e 
left join DEPARTMENT on(DEPT_CODE =DEPT_ID)
);

select * from emp_01;
->
emp_id|emp_name|eopt_title|
------+--------+----------+
   200|선동일     |총무부       |
   201|송종기     |총무부       |
   202|노옹철     |총무부       |
   203|송은희     |해외영업2부    |
   204|유재식     |해외영업2부    |
   205|정중하     |해외영업2부    |
   206|박나라     |해외영업1부    |
   207|하이유     |해외영업1부    |
   208|김해술     |해외영업1부    |
   209|심봉선     |해외영업1부    |
   210|윤은해     |해외영업1부    |
   211|전형돈     |기술지원부     |
   212|장쯔위     |기술지원부     |
   213|하동운     |          |
   214|방명수     |인사관리부     |
   215|대북혼     |해외영업1부    |
   216|차태연     |인사관리부     |
   217|전지연     |인사관리부     |
   218|이오리     |          |
   219|임시환     |회계관리부     |
   220|이중석     |회계관리부     |
   221|유하진     |회계관리부     |
   222|이태림     |기술지원부     |
   500|박길동     |인사관리부     |
   600|박잉석     |인사관리부     |
   200|선동일     |총무부       |
   201|송종기     |총무부       |
   202|노옹철     |총무부       |
   203|송은희     |해외영업2부    |
   204|유재식     |해외영업2부    |
   205|정중앙     |해외영업2부    |
   206|박나라     |해외영업1부    |
   207|하이유     |해외영업1부    |
   208|김해술     |해외영업1부    |
   209|심봉선     |해외영업1부    |
   210|윤은해     |해외영업1부    |
   211|전형돈     |기술지원부     |
   212|장쯔위     |기술지원부     |
   213|하동운     |          |
   214|방명수     |인사관리부     |
   215|대북혼     |해외영업1부    |
   216|차태연     |인사관리부     |
   217|전지연     |인사관리부     |
   218|이오리     |          |
   219|임시환     |회계관리부     |
   220|이중석     |회계관리부     |
   221|유하진     |회계관리부     |
   222|이태림     |기술지원부     |
   500|박길동     |인사관리부     |
   600|박잉석     |인사관리부     |
   
create table test0101
as select emp_id ,emp_name,dept_code,hire_date 
from EMPLOYEE ;

SELECT * from test0101;

-- UPDATE : 해당 테이블의 데이터를 수정하는 명령어
-- update 테이블명 set 컬럼명 = 바꿀값(where 조건식 )
-- UPDATE 실행 후 데이터의 개수는 변하지 않는다. 

create table DEPT_COPY
AS SELECT * FROM DEPARTMENT ;

SELECT * FROM DEPT_COPY;
->
DEPT_ID|DEPT_TITLE|LOCATION_ID|
-------+----------+-----------+
D1     |인사관리부     |L1         |
D2     |회계관리부     |L1         |
D3     |마케팅부      |L1         |
D4     |국내영업부     |L1         |
D5     |해외영업1부    |L2         |
D6     |해외영업2부    |L3         |
D7     |해외영업3부    |L4         |
D8     |기술지원부     |L5         |
D9     |총무부       |L1         |

-- D9부서를 총모부 ->  전략기획
UPDATE dept_copy set dept_title = '전략기획부'
where dept_id - 'd9'
->
DEPT_ID|DEPT_TITLE|LOCATION_ID|
-------+----------+-----------+
D1     |인사관리부     |L1         |
D2     |회계관리부     |L1         |
D3     |마케팅부      |L1         |
D4     |국내영업부     |L1         |
D5     |해외영업1부    |L2         |
D6     |해외영업2부    |L3         |
D7     |해외영업3부    |L4         |
D8     |기술지원부     |L5         |
D9     |전략기획부     |L1         |

-- 실습 1
-- 임플로이 테이블에서 주민번호가 말못 표기되어있는 사원들이 있다 .
-- 해당 사원을 찾아 사번 순으로 각 주민번호 앞자리를
-- '621230 ' '631126' ' 850705' 로 변경하는 업데이트 

SELECT EMP_ID,EMP_NO FROM EMPLOYEE e 
-- 200 201 214 

update EMPLOYEE set emp_no = concat('621230',substr(emp_no,7))
where emp_id = 200;

update EMPLOYEE set emp_no = concat ('631126',substr(emp_no,7))
where emp_id = 201;

update EMPLOYEE set emp_no = concat ('860705',substr(emp_no,7))
where emp_id = 214;

SELECT * from EMPLOYEE e ;

-- update 
-- 여러 행을 변경 여러컬럼의 값을 변경하고자할때 서브커리를 사용한 업데이트문
-- 셋컬럼 서브쿼리

create table emp_salary
as
select emp_id , emp_name , dept_code, salary , bonus
from EMPLOYEE ;

SELECT * from emp_salary where emp_name in('유재식',' 방명수');

update emp_salary
set SALARY = (select SALARY  from EMPLOYEE where emp_name = '유재식'),
	BONUS = (select BONUS from EMPLOYEE where emp_name = '유재식')
where emp_name = '방명수';

UPDATE EMP_SALARY
SET (SALARY , BONUS) = (SELECT SALARY,BONUS FROM emp_salary WHERE EMP_NAME = '유재식')
where emp_name in ('노옹철', '전형돈','정중하','하동운');

-- UPDATE 시에도 변경할 값이 해당 컬럼의 제약조건을 위배하지 않아야 한다 . 
DESC USER_FOREIGN_KEY ;
SELECT * FROM USER_GRADE;

-- 에러
UPDATE USER_FOREIGN_KEY
SET GRADE_CODE = 10
WHERE GRADE_CODE = -1 ;
-- DELETE 
-- 테이블의 행을 삭제하는 명어
-- 실행 후에는 테이블의 행의 개수가 줄어든다 .

create table test_delete
as select * from EMPLOYEE ;

SELECT * from test_delete;


commit;

-- 데이터 전체 삭제
DELETE from test_delete;

rollback;

TRANSACTION / DROP / VIEW / AUTO INCREAMENT

-- 트랜잭션 --
-- 정의 : 데이터를 처리하는 작업을 잘게 나눈 데이터처리의 최소 작업 단위
-- 하나의 트랜잭션으로 이루어진 작업 내용은 전체성공(저장) or 하나라도 실패하면
-- 전체 실패 (복구) , 각각의 작업마다 저장시점을 구분해서 commit(작업내역 저장/반영) / rollback (작업 내역 취소)

commit;

create table USER_TB(
NO INT UNIQUE,
ID VARCHAR(20) NOT NULL UNIQUE,
PW VARCHAR(20) NOT NULL
);

INSERT INTO USER_TB VALUES(1,'TEST01','PASS01');
INSERT INTO USER_TB VALUES(2,'TEST02','PASS02');

SELECT * FROM USER_TB;
->
NO|ID    |PW    |
--+------+------+
 1|TEST01|PASS01|
 2|TEST02|PASS02|
 3|TEST03|PASS03|
 4|TEST04|PASS04|

commit; -- 현재까지 작업한 DML(INSERT 두번) 내용을 DB에 반영(저장)

INSERT INTO USER_TB VALUES(3,'TEST03','PASS03');

SELECT * FROM USER_TB;

ROLLBACK;

SELECT * FROM USER_TB;

INSERT INTO USER_TB VALUES(3,'TEST03','PASS03');

-- 세이브 포인트 지정 --
SAVEPOINT SP1;

INSERT INTO USER_TB VALUES(4,'TEST04','PASS04');

SELECT * FROM USER_TB;
-- DELETE FROM USER_TB WHERE NO = 4;

ROLLBACK TO SP1; -- 해당 세이브포인트로 되돌아가겠다.


-- ALTER : 생성한 객체(TABLE , VIEW ...)를 수정 
DROP TABLE DEPT_COPY;
CREATE TABLE DEPT_COPY 
AS SELECT * FROM DEPARTMENT ;

SELECT * FROM DEPT_COPY;
->
DEPT_ID|DEPT_TITLE|LOCATION_ID|
-------+----------+-----------+
D1     |인사관리부     |L1         |
D2     |회계관리부     |L1         |
D3     |마케팅부      |L1         |
D4     |국내영업부     |L1         |
D5     |해외영업1부    |L2         |
D6     |해외영업2부    |L3         |
D7     |해외영업3부    |L4         |
D8     |기술지원부     |L5         |
D9     |전략기획부     |L1         |

-- 컬럼을 추가하기 
alter table DEPT_COPY  ADD LNAME VARCHAR(20);

SELECT * FROM DEPT_COPY;
->
DEPT_ID|DEPT_TITLE|LOCATION_ID|LNAME|
-------+----------+-----------+-----+
D1     |인사관리부     |L1         |     |
D2     |회계관리부     |L1         |     |
D3     |마케팅부      |L1         |     |
D4     |국내영업부     |L1         |     |
D5     |해외영업1부    |L2         |     |
D6     |해외영업2부    |L3         |     |
D7     |해외영업3부    |L4         |     |
D8     |기술지원부     |L5         |     |
D9     |전략기획부     |L1         |     |

-- 컬럼을 삭제하기 
ALTER TABLE DEPT_COPY DROP COLUMN LNAME;

DESC DEPT_COPY ;
Field      |Type       |Null|Key|Default|Extra|
-----------+-----------+----+---+-------+-----+
DEPT_ID    |varchar(10)|NO  |   |       |     |
DEPT_TITLE |varchar(35)|NO  |   |       |     |
LOCATION_ID|varchar(2) |NO  |   |       |     |

-- 컬럼 추가 ( 기본값 적용 )
ALTER TABLE DEPT_COPY  ADD LNAME VARCHAR(20) DEFAULT '한국' ;
SELECT * from DEPT_COPY;

-- 제약조건 추가
ALTER TABLE DEPT_COPY ADD CONSTRAINT PK_DEPT_CP PRIMARY KEY(DEPT_ID);

-- 타입의 크기 등 수정
ALTER TABLE DEPT_COPY MODIFY DEPT_ID VARCHAR(30);
DESC DEPT_COPY;


-- 테이블 이름 변경
ALTER TABLE DEPT_COPY 
RENAME TO DEPTCOPY;

SELECT * FROM DEPT_COPY;
SELECT * FROM DEPTCOPY;


-- DROP --
-- 객체의 특정 요소를 제거하거나 객체 자체를 제거할때 사용하는 명령어 . 
-- 1. 객체의 특정요소를 제거
-- alter 객체 객체명 
-- drop column 컬럼명;

-- 2. 객체 자체를 제거
-- drop 객체 객체명;

DROP TABLE DEPTCOPY;

-- VIEW(뷰) -- 
-- SELECT를 실행한 결과화면을 담는 객체 
-- SELECT 문장 자체를 저장.
-- 호출할떄마다 저장된 쿼리를 실행하여 결과를 보여주는 객체다 . 

-- 실질적으로 데이터를 담고 있지 않다.
-- 보통 노출하고 싶지 않은 정보다 , 업무에 불피룡한 정보를제외한 
-- 필요 정보들만 조회하고자 할 때 사용한다. 

-- CREATE [OR REPLACE] VIEW 뷰 이름 
-- AS 서브쿼리 (뷰에 저장하여 확인할 select 쿼리)

create or REPLACE VIEW V_EMP
AS SELECT EMP_ID, EMP_NAME, DEPT_CODE FROM EMPLOYEE ;

SELECT * FROM V_EMP;

CREATE OR REPLACE VIEW V_EMP(사번 , 사원명 , 부서 , 직급) 
AS SELECT EMP_ID , EMP_NAME , DEPT_CODE, JOB_CODE FROM EMPLOYEE;

SELECT * FROM V_EMP;

drop view V_EMP;

-- 
CREATE OR REPLACE VIEW V_RESULT_EMP(사번,이름명,직급명,부서명,근무지)
as 
select emp_id , emp_name, job_name , dept_title,local_name 
from EMPLOYEE 
left join JOB using(job_code)
left join DEPARTMENT on(dept_code=dept_id)
left join LOCATION on(location_id=local_code);

select * from V_RESULT_EMP;

-- VIEW는 SELECT 쿼리를 저장하고 있기에
-- 원본이 변경되었을때 뷰도 함께 변경해서 조회 가능하다. 

UPDATE EMPLOYEE 
SET EMP_NAME='정중앙'
WHERE EMP_ID='205';

SELECT * FROM EMPLOYEE;

COMMIT;

SELECT * FROM V_RESULT_EMP;

-- 뷰에는 연산결과를 포함한 SELECT문 저장 가능하다.
SELECT EMP_ID,EMP_NAME, 
		IF(SUBSTR(EMP_NO, 8 , 1 )=1, '남성','여성')
		from EMPLOYEE ;

create or replace view v_emp(사번,사원,성별)
as
select emp_id ,emp_name,
if(substr(emp_no,8,1)=1 ,'남','여')
from EMPLOYEE ;

select * from v_emp;

-- 뷰에 데이터 삽입 , 수정 , 삭제하기 
create or replace view V_JOB
as
select * from JOB ;

SELECT * from V_JOB;

-- 뷰를 통해 데이터 추가
INSERT into V_JOB
VALUES('J8','인턴');

select * from V_JOB;
select * from JOB;

-- 수정
UPDATE V_JOB
SET JOB_NAME = '알바'
WHERE JOB_CODE = 'J8';

SELECT * FROM V_JOB;
SELECT * FROM JOB;

-- 삭제 
DELETE FROM V_JOB
WHERE JOB_CODE = 'J8';

SELECT * FROM V_JOB;
SELECT * FROM JOB ;

-- auto_increament
-- INSERT 할 때 자동으로 키를 1씩 증가 .

CREATE TABLE AT_TEST(
ID INT AUTO_INCREMENT PRIMARY KEY,
NAME VARCHAR(30)
);


select last_insert_id();

TRANSACTION / DROP / VIEW / AUTO INCREAMENT

'mySQL' 카테고리의 다른 글

[mySQL]그룹에 관련된 명령어  (0) 2024.04.01
[mySQL]연산자 , 함수  (0) 2024.03.29
[mySQL] 데이터베이스  (0) 2024.03.24