간단한 테이블 생성 테스트를 위해 person 테이블과 각 사람이 좋아하는 음식에 대한 favorite_food 테이블을 만들어보도록 하겠습니다.
(성, 이름, 눈동자색, 생일, 주소) 정보 등이 담긴 person 테이블 생성을 위해서는 아래와 같은 SQL 스키마 문을 입력하면 됩니다.
MariaDB [sakila]> CREATE TABLE person
-> (person_id SMALLINT UNSIGNED,
-> fname VARCHAR(20),
-> lname VARCHAR(20),
-> eye_color ENUM('BR', 'BL', 'GR'),
-> birth_date DATE,
-> street VARCHAR(30),
-> city VARCHAR(20),
-> state VARCHAR(20),
-> country VARCHAR(20),
-> postal_code VARCHAR(20),
-> CONSTRAINT pk_person PRIMARY KEY (person_id)
-> );
Query OK, 0 rows affected, 1 warning (0.023 sec)
MariaDB [sakila]> desc person;
+-------------+----------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------+----------------------+------+-----+---------+-------+
| person_id | smallint(5) unsigned | NO | PRI | NULL | |
| fname | varchar(20) | YES | | NULL | |
| lname | varchar(20) | YES | | NULL | |
| eye_color | enum('BR','BL','GR') | YES | | NULL | |
| birth_date | date | YES | | NULL | |
| street | varchar(30) | YES | | NULL | |
| city | varchar(20) | YES | | NULL | |
| state | varchar(20) | YES | | NULL | |
| country | varchar(20) | YES | | NULL | |
| postal_code | varchar(20) | YES | | NULL | |
+-------------+----------------------+------+-----+---------+-------+
10 rows in set (0.005 sec)
MariaDB [sakila]> CREATE TABLE favorite_food
-> (person_id SMALLINT UNSIGNED,
-> food VARCHAR(20),
-> CONSTRAINT pk_favorite_food PRIMARY KEY (person_id, food),
-> CONSTRAINT fk_fav_food_person_id FOREIGN KEY (person_id)
-> REFERENCES person (person_id)
-> );
Query OK, 0 rows affected, 1 warning (0.023 sec)
person_id와 food 모두가 PRIMARY KEY로 설정된 것을 확인할 수 있습니다.
MariaDB [sakila]> desc favorite_food;
+-----------+----------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------+----------------------+------+-----+---------+-------+
| person_id | smallint(5) unsigned | NO | PRI | NULL | |
| food | varchar(20) | NO | PRI | NULL | |
+-----------+----------------------+------+-----+---------+-------+
2 rows in set (0.004 sec)
테이블에 데이터를 삽입할 때, 기본 키(person 테이블의 경우 person_id) 값이 자동으로 제공되도록 수정해야합니다. 이 때, 외래 키 제약조건으로 인해 곧바로 수정이 불가능하므로, 아래와 같이 제약 조건을 풀어주고 작업을 수행해야 합니다.
set foreign_key_checks=0; /* 제약조건 해제 */
ALTER TABLE person MODIFY person_id SMALLINT UNSIGNED AUTO_INCREMENT; /* 자동 증가 기능 추가 */
set foreign_key_checks=1; /* 제약조건 재설정 */
위 스키마 문을 적용한 후, 다시 테이블을 확인해보면 person_id의 Extra 부분에 auto_increment가 들어있음을 확인할 수 있습니다.
MariaDB [sakila]> desc person;
+-------------+----------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+----------------------+------+-----+---------+----------------+
| person_id | smallint(5) unsigned | NO | PRI | NULL | auto_increment |
person 테이블에 Harry Porter를 추가해보겠습니다.
MariaDB [sakila]> INSERT INTO person
-> (fname, lname, eye_color, birth_date)
-> VALUES ('Harry', 'Porter', 'GR', '1980-07-31');
Query OK, 1 row affected (0.002 sec)
이 때, 주소와 관련된 어떤 열도 값을 제공하지 않았지만 각 열들이 null을 허용하므로 문제없이 저장됩니다. 아래와 같은 명령어를 통해 정상적으로 값이 저장되었는지 확인할 수 있습니다.
MariaDB [sakila]> SELECT person_id, fname, lname, birth_date FROM person;
+-----------+-------+--------+------------+
| person_id | fname | lname | birth_date |
+-----------+-------+--------+------------+
| 1 | Harry | Porter | 1980-07-31 |
+-----------+-------+--------+------------+
1 row in set (0.001 sec)
Harry Porter가 좋아하는 음식들도 추가해보겠습니다.
MariaDB [sakila]> INSERT INTO favorite_food (person_id, food)
-> VALUES (1, 'pizza');
Query OK, 1 row affected (0.001 sec)
MariaDB [sakila]> INSERT INTO favorite_food (person_id, food)
-> VALUES (1, 'cookies');
Query OK, 1 row affected (0.001 sec)
MariaDB [sakila]> INSERT INTO favorite_food (person_id, food)
-> VALUES (1, 'nachos');
Query OK, 1 row affected (0.001 sec)
알파벳 순서로 Harry Porter가 좋아하는 음식을 조회해보겠습니다.
MariaDB [sakila]> SELECT food
-> FROM favorite_food
-> WHERE person_id = 1
-> ORDER BY food;
+---------+
| food |
+---------+
| cookies |
| nachos |
| pizza |
+---------+
3 rows in set (0.001 sec)
처음 생성시에 입력하지 않았던 해리포터의 주소를 UPDATE 문을 이용해 추가해보겠습니다.
MariaDB [sakila]> UPDATE person
-> SET street = '4 Privet Drive',
-> city = 'Little Whinging',
-> state = 'Surrey',
-> country = 'UK',
-> postal_code = 'WD25 7FD'
-> WHERE person_id = 1;
Query OK, 1 row affected (0.001 sec)
Rows matched: 1 Changed: 1 Warnings: 0
정상적으로 반영되었는지 한 번 확인해보겠습니다.
MariaDB [sakila]> SELECT * FROM person WHERE person_id = 1;
+-----------+-------+--------+-----------+------------+----------------+-----------------+--------+---------+-------------+
| person_id | fname | lname | eye_color | birth_date | street | city | state | country | postal_code |
+-----------+-------+--------+-----------+------------+----------------+-----------------+--------+---------+-------------+
| 1 | Harry | Porter | GR | 1980-07-31 | 4 Privet Drive | Little Whinging | Surrey | UK | WD25 7FD |
+-----------+-------+--------+-----------+------------+----------------+-----------------+--------+---------+-------------+
1 row in set (0.000 sec)
제약조건에 위배되게 데이터를 생성하거나 수정하려고 할 경우 문제들이 생길 수 있습니다.
테이블에 이미 person_id=1 인 Harry Porter가 있을 때, 같은 id로 Hermione Granger를 추가하려고 하면 아래와 같이 실패합니다.
MariaDB [sakila]> INSERT INTO person
-> (person_id, fname, lname, eye_color, birth_date)
-> VALUES (1, 'Hermione', 'Granger', 'BR', '1979-09-19');
ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY'
존재하지 않는 person_id 에 대해 favorite_food를 추가하려고 하면 아래와 같이 실패합니다.
MariaDB [sakila]> INSERT INTO favorite_food (person_id, food)
-> VALUES (2, 'chicken');
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails
(`sakila`.`favorite_food`, CONSTRAINT `fk_fav_food_person_id` FOREIGN KEY (`person_id`) REFERENCES `person` (`person_id`))
외래 키 제약조건은 InnoDB 스토리지 엔진을 사용하여 테이블을 생성했을 때만 적용할 수 있다고 합니다.
person 테이블의 eye_color 처럼 가능한 값이 제한된 열의 경우 다른 값을 지정하려고 하면 아래와 같이 실패합니다. 에러 메세지가 조금 이상하네요.
MariaDB [sakila]> UPDATE person
-> SET eye_color = 'WH'
-> WHERE person_id = 1;
ERROR 1265 (01000): Data truncated for column 'eye_color' at row 1
date 열의 값으로 제공하는 문자열이 기본 형식에 어긋날 경우 아래와 같이 실패합니다.
MariaDB [sakila]> UPDATE person
-> SET birth_date = '07-31-1980'
-> WHERE person_id = 1;
ERROR 1292 (22007): Incorrect date value: '07-31-1980' for column `sakila`.`person`.`birth_date` at row 1
다른 형식의 값으로 데이터를 업데이트하고 싶을 경우 str_to_date
함수를 아래와 같이 활용하면 됩니다.
MariaDB [sakila]> UPDATE person
-> SET birth_date = str_to_date('08-31-1980', '%m-%d-%Y')
-> WHERE person_id = 1;
Query OK, 1 row affected (0.002 sec)
Rows matched: 1 Changed: 1 Warnings: 0
delete 문을 활용하면 해당하는 행을 삭제할 수 있습니다.
MariaDB [sakila]> DELETE FROM person WHERE person_id = 2;
Query OK, 1 row affected (0.001 sec)
마지막으로 예시로 만든 테이블을 삭제해보도록 하겠습니다.
MariaDB [sakila]> DROP TABLE favorite_food;
Query OK, 0 rows affected (0.003 sec)
MariaDB [sakila]> DROP TABLE person;
Query OK, 0 rows affected (0.003 sec)
이 글 및 이와 관련된 앞으로의 글의 모든 내용은 한빛미디어의 러닝 SQL의 내용을 공부하며 요약한 것입니다.