위의 사진 처럼 연결되어 있는 schema를 살펴보자. 위처럼 테이블을 만들어주기 위해 migrations/schema.sql의 part 5의 주석을 내용을 채워보자.
CREATE TABLE `category` (
-- TODO: id, name 추가하기
`id` int PRIMARY KEY AUTO_INCREMENT,
`name` varchar(255)
);
CREATE TABLE `content_category` (
-- TODO: 조인테이블 만들기. id, contentId, categoryId 만들기
`id` int PRIMARY KEY AUTO_INCREMENT,
`contentId` int NOT NULL, FOREIGN KEY (`contentId`) REFERENCES `content` (`id`),
`categoryId` int NOT NULL, FOREIGN KEY (`categoryId`) REFERENCES `category`(`id`)
);
CREATE TABLE `role` (
-- TODO: id, name 추가하기
`id` int PRIMARY KEY AUTO_INCREMENT,
`name` varchar(255)
);
ALTER TABLE `user` ADD roleId int;
ALTER TABLE `user` ADD FOREIGN KEY (`roleId`) REFERENCES `role` (`id`);
CREATE TABLE `category` (
-- TODO: id, name 추가하기
`id` int PRIMARY KEY AUTO_INCREMENT,
`name` varchar(255)
);
mysql> SELECT * FROM category;
+----+--------+
| id | name |
+----+--------+
| 1 | soccer |
| 2 | family |
| 3 | health |
+----+--------+
3 rows in set (0.00 sec)
위의 코드를 이용해서 category라는 테이블을 만들어본다. 그 안의 데이터로는 Primary key를 가질 수 있도록 id를 만들고, 정수인 int로 선언한다. 이후 PRIMARY KEY AUTO_INCREMENT로 데이터가 추가 될 때, 자동적으로 Primary Key가 생성 될 수 있도록 한다.
CREATE TABLE `content_category` (
-- TODO: 조인테이블 만들기. id, contentId, categoryId 만들기
`id` int PRIMARY KEY AUTO_INCREMENT,
`contentId` int NOT NULL, FOREIGN KEY (`contentId`) REFERENCES `content` (`id`),
`categoryId` int NOT NULL, FOREIGN KEY (`categoryId`) REFERENCES `category`(`id`)
);
mysql> SELECT * From content_category;
+----+-----------+------------+
| id | contentId | categoryId |
+----+-----------+------------+
| 1 | 1 | 1 |
| 2 | 1 | 3 |
| 3 | 2 | 2 |
| 4 | 2 | 1 |
+----+-----------+------------+
4 rows in set (0.00 sec)
content와 category는 현재 N:N의 관계에 있다. 하여 1:N의 관계를 만들기 위해서, join table인 content_category를 만드는 것이다.
위와 같이 PRIMARY KEY AUTO_INCREMENT로 데이터가 추가 될 때, 자동적으로 Primary Key가 생성 될 수 있도록 한다. contentId와 categoryId는 Foreign Key로 들어가 있기 때문에, 정수인 int로 선언 해주며, Foreign Key로 설정해주기 위해서 FOREIGN KEY(’contentId’)로 선언한다. 또한 Foreign Key는 content 테이블의 Primary Key 참조 하기 때문에 REFERENCE content
(id
)로 선언해준다.
int NOT NULL을 설정해 준 이유는, id와 같은 민감한 데이터는 없으면 오류가 나야하기 때문이라고 한다. (설정해 주지 않으면, 따로 id값이 없다고 오류가 나지 않나보다.)
CREATE TABLE `role` (
-- TODO: id, name 추가하기
`id` int PRIMARY KEY AUTO_INCREMENT,
`name` varchar(255)
);
mysql> SELECT * FROM role;
+----+----------+
| id | name |
+----+----------+
| 1 | attacker |
| 2 | defense |
+----+----------+
2 rows in set (0.00 sec)
category 테이블에서 만들었던것과 같은 내용이다.
ALTER TABLE `user` ADD roleId int;
ALTER TABLE `user` ADD FOREIGN KEY (`roleId`) REFERENCES `role` (`id`);
mysql> SELECT * FROM user;
+----+-------------+-------------------------------+--------+
| id | name | email | roleId |
+----+-------------+-------------------------------+--------+
| 1 | jiSungPark | jisung.park@manchester.united | 1 |
| 2 | woonJaeLee | woonJae.Lee@goal.keeper | NULL |
| 3 | youngPyoLee | youngPyo.Lee@shadow.leg | 2 |
| 4 | myungBoHong | myungBo.Hong@korea.joojang | 2 |
| 5 | duRiCha | duRi.Cha@run.fast | 2 |
+----+-------------+-------------------------------+--------+
5 rows in set (0.00 sec)
ALTER TABLE을 이용해서 user 테이블에 roleId를 추가한다. user와 role 테이블은 1:N의 관계를 가지고 있으므로, user 테이블에서 roleId를 참조하여 Foreign Key를 갖고 있게 한다.
DESC category
SELECT category.id, category.name FROM category
SELECT user.name, user.email role.name AS roleName FROM user left JOIN role ON user.roleId=role.id
위 문제를 다시 보면 속한 role이 없다는 것은 해당 값이 NULL일 경우에도 해당 값을 모두 찾아야한다는 의미이다. 그렇기 때문에 기준이되는 user를 기준으로 하는 left join으로 role이 NULL값인 것도 불러올 수 있도록 한다.
user와 role 테이블에는 name이라는 필드가 같이 존재한다. 그렇기때문에 해당 name이 어디에 속해있는 값인지 명확하게 해줄 필요가 있다. user에만 존재하는 email은 그냥 써도 무관하지만, 정확한 확인을 위하여 써주는 것이 좋겠다.
SELECT * FROM user WHERE roleId IS NULL
role에 속하지 않는 user의 모든 컬럼 데이터라는 말은 곧, user와 role이 JOIN이 될 PK나 FK가 존재하지 않는다는 말과 같다. user의 데이터를 보면 roleId가 NULL인 값이 있는데 이 부분을 출력할 수 있는 구문을 만들면 되겠다.
SELECT * FROM content_category
SELECT title FROM content JOIN user ON content.userId=user.id WHERE user.name='jiSungPark'
content에는 jiSungPark이라는 데이터가 저장되어 있는 name항목이 존재하지 않는다. 이 항목은 user 테이블에서 찾아와야하므로 content와 user가 JOIN이 되어야 한다. 이후 name의 값이 jiSungPark인 경우만 찾아와야 하므로 WHERE으로 조건을 붙여 결과를 출력하면 되겠다.
SELECT category.name FROM category
JOIN content_category ON category.id=content_category.categoryId
JOIN content ON content_category.contentId=content.id
JOIN user ON content.userId=user.id
WHERE user.name='jiSungPark'
SELECT content.title, content.body, content.created_at FROM content
JOIN content_category ON content.id=content_category.contentId
JOIN category ON content_category.categoryId=category.id
WHERE category.name='soccer'
SELECT content.title, content.body, content.created_at, user.name FROM user
JOIN content ON user.id=content.userId
JOIN content_category ON content.id=content_category.contentId
JOIN category ON content_category.categoryId=category.id
WHERE category.name='soccer'
SELECT COUNT(title) AS ContentCount FROM content
JOIN user ON content.userId=user.id
WHERE user.name='duRiCha'
SELECT user.name AS name, COUNT(title) AS ContentCount FROM content
right JOIN user ON content.userId=user.id
GROUP BY user.name