MySQLの構造を理解する
MySQLにログインするとそこからどこのデータベースを使うか選択する事になります。
その各データベースの中には Table(テーブル) と呼ばれるデータを分類する箱のようなものがあります。
その中にあるデータに対して作成、更新、抽出、削除などを行なっていきます。
MySQLの中にデータベースがあって、その中にテーブルがあるという構造になっています。
データベースを作る
データベースはCREATE DATABASE データベース名;
で作成できます。
例えばCREATE DATABASE sample_db;
みたいな感じでsample_db
というデータベースを作れます。
データベースが出来たのかの確認はSHOW DATABASES;
で確認できます。CREATE DATABASEで作成したデータベースの名前があればOKです。
テーブルを作る
データベースが出来たら、USE データベース名;
で使用するデータベースを選択します。今回はUSE sample_db;
で先ほど作成したデータベースを利用します。
今回はuserというテーブルを作ってみたいと思います。
テーブルの作成は以下のSQL文でできます。
CREATE TABLE user (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`address` varchar(255),
PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8mb4;
userテーブルには名前と住所を保存する場所があります。このidやname、addressのようなものを カラム(column) と呼びます。
idはPRIMARY KEY (id)
という定義がされています。これはidは絶対に重複しないものしか入らないという意味になります。
定義されたid、name、addressの後にint
やvarchar(255)
などがあります。これは型と呼びます。
int
はintegerの略で整数しか登録できない事を指します。
varchar
はCHARACTER VARYINGの略で可変長の文字列という意味で文字列を意味します。255というのは255文字まで登録できるという意味になります。他にもTEXTなど文字数に制限のない(制限はあるけど)ものもありますが、メモリの都合上できるだけ文字数は制限できた方が良いです。
NOT NULL
が付いているものがあります。これが空のデータの時は登録に失敗します。
idについているAUTO_INCREMENT
というのは自動的に1からプラスして増えていくという意味になります。その為、絶対に被らないのでPRIMARY KEY
に使用される事が多いです。
DEFAULT CHARSET=utf8mb4
というのは何も指定しない場合は、utf8mb4
という文字コードを使用するという意味になります。文字コードはたくさんある為、説明は省きますが一般的にutf8mb4を使用していただければ問題ないと思います。
データを投入する
データの投入はINSERT文を使用します。INSERT INTO テーブル名 (カラム名1) VALUES ('データ1');
で記述します。
INSERT
INTO user
(name, address)
VALUES
('鈴木', '愛知県');
一気に複数の入力をする場合はvaluesをカンマ区切りで複数記述します。
INSERT
INTO user
(name, address)
VALUES
('佐藤', '北海道'),
('高橋', '東京都'),
('田中', '大阪');
これで鈴木、佐藤、高橋、田中の4つのデータができたと思います。
データを抽出する
データを抽出はSELECT文を使用します。SELECT カラム名 FROM テーブル名;
で記述します。
SELECT name FROM user;
これでnameの一覧を取得する事ができます。SELECTで*(アスタリスク)
を使うとワイルドカードと呼ばれ、全てのカラムという意味になります。
以下の場合は、userのid, name, addressの全てを表示します。
SELECT * FROM user;
WHERE文で絞り込む
WHERE文を使うと指定したいものを絞り込む事ができます。
SELECT * FROM user
WHERE id = 1;
ユーザーに紐付く情報を作成する
postというユーザーのブログの投稿を保存するテーブルを作成します。
user_idというカラムを利用してユーザーのidと紐付けます。
CREATE TABLE post (
`id` int NOT NULL AUTO_INCREMENT,
`title` varchar(255) NOT NULL,
`article` varchar(255),
`user_id` INT NOT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8mb4;
postにデータを投入します。
INSERT
INTO post
(title, article, user_id)
VALUES
('普通のタイトル', '普通の記事', 2),
('タイトル', '退屈な記事', 3),
('素晴らしいタイトル', '素晴らしい記事', 3),
('不思議なタイトル', '不思議な記事', 4),
('何かのタイトル', '何かの記事', 1),
('悲しいタイトル', '悲しい記事', 3);
データを紐付けて抽出する
誰がどの投稿をしたのか今の状況だとわかりにくいです。その為、ユーザー情報と投稿情報を紐付けたいと思います。
紐付ける時はJOIN
やLEFT JOIN
、RIGHT JOIN
という文をSELECT文に組み合わせて使います。
SELECT *
FROM user
JOIN post
ON user.id = post.user_id;
やってる順番としては、まずFROM user
でユーザー情報を呼び出します。
その情報に対してJOIN post
で投稿を紐付ける宣言をします。
どの情報を紐付けるかをON
で記述します。
書き方はテーブル名.カラム名
になります。今回はuser.id
やpost.user_id
になります。
複数のテーブルを跨いだSELECTの書き方
今までのSELECT文は一つのテーブルだったので、そのままカラム名を書けばいいだけでした。
しかし複数のテーブルを組み合わせた場合にカラム名が重複する場合があります。
その場合はテーブル名.カラム名
表現できます。
しかし以下のSQLを実行するとuser.id
とpost.id
が同じidというカラム名で表記されてしまいます。
SELECT user.id, user.name, post.id
FROM user
JOIN post
ON user.id = post.user_id;
その場合はas
というのを使って、以下のように別名に変換できます.
SELECT user.id as 'ユーザーのid', user.name, post.id as '投稿ののid'
FROM user
JOIN post
ON user.id = post.user_id;
重複しない場合はテーブル名を書かずSELECTできます。
postのデータの問題点
このデータの持ち方には問題が発生する場合があります。
今回投稿は1投稿者に対して記事を複数持つことができますが、共同編集など記事を共有する事ができません。
その為、中間テーブルという手法を用いる事で解決していきます。
中間テーブルを作成するためのデータ作り
今回は記事に対して、複数のユーザーを紐付けたいと思います。
それと記事に対して、タグを付けていきたいと思います。
userとpostの中間テーブル
userのidとpostのidの関係のみを抽出します。
# テーブル作成
CREATE TABLE user_post (
`id` int NOT NULL AUTO_INCREMENT,
`user_id` INT NOT NULL,
`post_id` INT NOT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8mb4;
# データ投入
INSERT
INTO user_post
(user_id, post_id)
VALUES
(1, 1),
(2, 1),
(1, 2),
(3, 3),
(2, 4),
(4, 4),
(1, 5),
(3, 6);
tagテーブル
# テーブル作成
CREATE TABLE tag (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8mb4;
# データ投入
INSERT
INTO tag
(name)
VALUES
('スポーツ'),
('ビジネス'),
('エンタメ'),
('ファッション'),
('海外');
postとtagの中間テーブル
postのidとtagのidの関係のみを抽出します。
# テーブル作成
CREATE TABLE post_tag (
`id` int NOT NULL AUTO_INCREMENT,
`post_id` INT NOT NULL,
`tag_id` INT NOT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8mb4;
# データ投入
INSERT
INTO post_tag
(post_id, tag_id)
VALUES
(2, 1),
(2, 3),
(2, 5),
(3, 2),
(3, 3),
(4, 4),
(4, 5),
(5, 1),
(5, 4),
(6, 2);
user_postテーブルを使ってユーザーに紐づいてる記事を抽出する
ちょっと複雑なSQL文の考え方
1. まずはSELECT * FROM テーブル名;をする
SELECT * FROM `user`;
2. 次に紐付けるものをJOINする
いきなりpostとJOINしたくなるけど、先に中間テーブルとJOINする。
SELECT * FROM `user`
JOIN user_post
ON `user`.id = user_post.user_id;
3. 中間テーブルと本当にJOINしたかったものとJOINする
SELECT * FROM `user`
JOIN user_post
ON `user`.id = user_post.user_id
JOIN post
ON post.id = user_post.id;
4. 最後に抽出したいものだけSELECTにし、見やすくする
SELECT user.id as 'ユーザーid', name as '投稿者', title as '記事のタイトル', article as '本文' FROM `user`
JOIN user_post
ON `user`.id = user_post.user_id
JOIN post
ON post.id = user_post.id;
練習問題
タグから検索して、タグ名、投稿者、記事のタイトル、本文を抽出してください。
SELECT
tag.`name` as 'タグ名',
`user`.name as '投稿者',
post.title as '記事のタイトル',
post.article as '本文'
FROM tag
JOIN post_tag
ON post_tag.tag_id = tag.id
JOIN post
ON post.id = post_tag.post_id
JOIN user_post
ON user_post.post_id = post.id
JOIN user
ON user.id = user_post.user_id;
WHERE tag.id = 1;