CodeGym /행동 /SQL SELF /ON DELETE CASCADEON UPDATE RESTRICT...

ON DELETE CASCADEON UPDATE RESTRICT 사용하기

SQL SELF
레벨 19 , 레슨 2
사용 가능

상상해봐, 너가 데이터베이스를 만들었는데, 거기엔 고객(customers) 테이블이랑 그 고객과 연결된 주문(orders) 테이블이 있어. 근데 어느 순간 이런 고민이 생길 수 있지: 만약에 customers에서 고객을 삭제하면 어떻게 해야 할까? 그 고객의 주문도 같이 삭제해야 할까, 아니면 주문이 "고아"처럼 남아서 존재하지 않는 고객을 참조하게 둘까? 그리고 만약에 고객의 ID를 바꾸고 싶으면? 바로 이런 상황에서 cascade 연산(CASCADE)이랑 제약조건(RESTRICT)이 데이터베이스 동작을 제어하는 데 등장하는 거야.

ON DELETE CASCADE는 부모 테이블에서 레코드를 삭제하면 연결된 레코드도 자동으로 삭제해주는 메커니즘이야. 즉, 고객을 삭제하면 그 고객과 연결된 모든 주문도 같이 삭제돼.

이건 이렇게 동작해. 외래키 정의에 ON DELETE CASCADE를 추가하면, 데이터베이스가 "아, 연결된 레코드도 같이 지워야겠구나"라고 알아서 처리해줘.

예시

예를 들어, customersorders 두 테이블이 있다고 해보자. 고객(customers)은 여러 개의 주문(orders)을 가질 수 있고, 이건 ONE-TO-MANY 관계야. 우리는 고객을 삭제하면 그 고객의 주문도 다 같이 삭제되길 원해.

-- 고객 테이블 만들기
CREATE TABLE customers (
    customer_id SERIAL PRIMARY KEY,
    name TEXT NOT NULL
);

-- 고객 테이블을 참조하는 외래키가 있는 주문 테이블 만들기
CREATE TABLE orders (
    order_id SERIAL PRIMARY KEY,
    customer_id INT REFERENCES customers(customer_id) ON DELETE CASCADE,
    order_date DATE NOT NULL
);

테이블에 데이터 넣기

-- 고객 테이블에 데이터 넣기
INSERT INTO customers (name) VALUES ('이반'), ('안나');

-- 주문 테이블에 데이터 넣기
INSERT INTO orders (customer_id, order_date) VALUES
(1, '2023-10-01'),
(1, '2023-10-02'),
(2, '2023-10-03');

orders 테이블:

order_id customer_id order_date
1 1 2023-10-01
2 1 2023-10-02
3 2 2023-10-03

고객 삭제하고 결과 확인하기

-- ID가 1인 고객 삭제
DELETE FROM customers WHERE customer_id = 1;

-- 주문 테이블에 뭐가 남았는지 확인
SELECT * FROM orders;
order_id customer_id order_date
3 2 2023-10-03

보다시피, 삭제된 고객과 연결된 주문도 같이 삭제됐어.

변경 제한: ON UPDATE RESTRICT

ON UPDATE RESTRICT는 부모 테이블의 값을 자식 테이블이 참조하고 있을 때, 그 값을 바꾸지 못하게 막아주는 "보호막" 같은 거야. 데이터 무결성을 깨뜨릴 수 있는 변경을 막아주는 거지.

어떻게 동작하냐면, ON UPDATE RESTRICT를 외래키에 추가하면, 부모 테이블의 키를 자식 테이블이 참조하고 있으면 그 키를 바꿀 수 없어.

예시

아까 그 customersorders 테이블을 그대로 쓰는데, 이번엔 외래키에 변경 제한을 추가해볼게.

-- 주문 테이블을 변경 제한 옵션으로 다시 만들기
DROP TABLE orders;

CREATE TABLE orders (
    order_id SERIAL PRIMARY KEY,
    customer_id INT REFERENCES customers(customer_id) ON UPDATE RESTRICT,
    order_date DATE NOT NULL
);

고객 ID를 바꿔보자

-- 고객 ID 2를 5로 바꿔보려고 시도
UPDATE customers 
SET customer_id = 5 
WHERE customer_id = 2;

결과:

ERROR:  update or delete on table "customers" violates foreign key constraint
DETAIL:  Key (customer_id)=(2) is still referenced from table "orders".

보다시피, 데이터베이스가 에러를 던졌어. 키를 바꾸면 테이블 간의 연결이 깨질 수 있으니까 막아준 거지.

UPDATE랑 그 동작의 디테일은 다음 레벨에서 더 자세히 알려줄게 :P

ON DELETE CASCADEON UPDATE RESTRICT 같이 쓰기

당연히, cascade 연산(CASCADE)이랑 제약조건(RESTRICT)은 같이 쓸 수 있어. 예를 들어, 부모 레코드를 삭제할 때 연결된 데이터를 자동으로 삭제(ON DELETE CASCADE)하면서, 그 ID는 바꿀 수 없게(ON UPDATE RESTRICT) 막을 수도 있지. 이렇게 하면 원치 않는 결과를 막을 수 있어.

예시

이번엔 두 옵션을 다 써서 주문 테이블을 다시 만들어보자:

DROP TABLE orders;

CREATE TABLE orders (
    order_id SERIAL PRIMARY KEY,
    customer_id INT REFERENCES customers(customer_id)
        ON DELETE CASCADE
        ON UPDATE RESTRICT,
    order_date DATE NOT NULL
);

이제:

  • 고객을 삭제하면 그 고객의 주문도 다 같이 삭제돼.
  • 고객의 ID를 바꾸려고 하면 에러가 나와.

실제 프로젝트에서 왜 중요할까?

CASCADERESTRICT는 테이블이 많고 복잡한 시스템에서 진짜 중요해. 예를 들어:

온라인 쇼핑몰에서 고객이 주문을 할 수 있잖아. 만약 고객이 자기 프로필을 삭제하면, 더 이상 참조되지 않는 주문이 데이터베이스에 남아있으면 안 되겠지? 이럴 때 ON DELETE CASCADE가 딱이야.

반대로, 유니크 키를 실수로 바꿔서 테이블 간의 연결이 깨지는 걸 막고 싶을 때는 ON UPDATE RESTRICT가 필요해.

코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION