다음 두 테이블이 있다.
CREATE TABLE users (
id INTEGER NOT NULL PRIMARY KEY,
userName VARCHAR(50) NOT NULL
);
CREATE TABLE roles (
id INTEGER NOT NULL PRIMARY KEY,
role VARCHAR(20) NOT NULL
);
usersRoles 테이블은 사용자와 역할(roles) 사이의 다대다(M:N) 관계를 표현한다.
다음 조건을 만족하도록 usersRoles 테이블 생성문을 수정하라(오직 이 CREATE 문장만 수정).
요구사항
usersRoles에는 반드시 users 테이블에 존재하는 사용자만 들어갈 수 있어야 한다.usersRoles에는 반드시 roles 테이블에 존재하는 역할만 들어갈 수 있어야 한다.(userId, roleId) 조합은 유일해야 함)초기 미완성 문장:
-- 수정 전 (변경 금지)
CREATE TABLE usersRoles (
userId INTEGER,
roleId INTEGER
);
CREATE TABLE usersRoles (
userId INT NOT NULL,
roleId INT NOT NULL,
PRIMARY KEY (userId, roleId), -- (userId, roleId) 조합을 유일하게 보장
CONSTRAINT fk_usersroles_user FOREIGN KEY (userId) REFERENCES users(id) ON DELETE CASCADE,
CONSTRAINT fk_usersroles_role FOREIGN KEY (roleId) REFERENCES roles(id) ON DELETE RESTRICT
);
설명 요지:
NOT NULL로 비어있는 값 금지.PRIMARY KEY (userId, roleId)로 동일 조합의 중복 삽입을 막음.FOREIGN KEY로 참조 무결성 보장(사용자·역할이 실제로 존재해야 함).ON DELETE동작은 설계 정책에 따라CASCADE(사용자 삭제 시 매핑 자동 삭제) 또는RESTRICT/NO ACTION(참조 존재하면 삭제 금지)를 선택할 수 있다.
INSERT INTO users (id, userName) VALUES (1, 'alice'), (2, 'bob');
INSERT INTO roles (id, role) VALUES (10, 'admin'), (20, 'editor');
INSERT INTO usersRoles (userId, roleId) VALUES (1, 10); -- 성공
INSERT INTO usersRoles (userId, roleId) VALUES (1, 20); -- 성공
INSERT INTO usersRoles (userId, roleId) VALUES (1, 10);
-- 에러: 중복된 PRIMARY KEY (userId, roleId) 이므로 삽입 불가
INSERT INTO usersRoles (userId, roleId) VALUES (999, 10);
-- 에러: fk_usersroles_user 참조 위배 (users.id에 999 없음)
DELETE FROM users WHERE id = 1;
-- usersRoles에 (1,10)·(1,20) 행이 자동으로 삭제된다 (CASCADE)
PRIMARY KEY (userId, roleId) (합성 PK)
id가 편리할 수 있다.대안으로 id(AUTO_INCREMENT)를 추가하고 (userId, roleId)에 UNIQUE 제약을 둘 수도 있다.
ON DELETE CASCADE: 사용자(또는 역할) 삭제 시 매핑도 자동 삭제. 편리하지만 실수로 사용자 삭제하면 매핑도 날아간다.ON DELETE RESTRICT 또는 기본 NO ACTION: 참조가 있으면 사용자를 못 지우게 해서 데이터 무결성을 강하게 보장.InnoDB이어야 한다. (MyISAM은 FK 무시)(userId, roleId)로 하는 조회(특정 user의 role 체크, 특정 role의 user 체크)에 적절한 인덱스가 이미 존재한다.Q1. usersRoles에 NULL을 허용해도 되나?
A1. 권장하지 않는다. userId와 roleId가 NULL이면 의미 없는 매핑이므로 NOT NULL로 강제한다.
Q2. 복합 PK 대신 id + UNIQUE (userId, roleId)를 쓰는 이유는?
A2. 매핑에 추가 컬럼(할당일, 활성여부 등)이 많아지거나 외부에서 매핑 row를 고유하게 참조해야 하는 경우 id가 유용하다.
Q3. FK의 ON DELETE는 어떤게 안전한가?
A3. 안전성 관점에서는 RESTRICT(삭제 차단)가 더 보수적이다. 자동 청소(CASCADE)가 편리하지만 의도치 않은 데이터 삭제 위험이 있다.
다대다 관계 테이블은
NOT NULL+FOREIGN KEY로 참조 무결성을 보장하고,(userId, roleId)에 복합 기본키(또는 UNIQUE)를 두어 동일 매핑의 중복 삽입을 방지해야 한다.