【MySQL】少し踏み込んだMySQLの基本的な文法

#はじめに

本記事は[【MySQL】基本的な文法やデータ型についてまとめてみた。](https://qiita.com/Kai_82/items/54158d97bbd900a311d3)の続きです。
そちらをご覧になっていない方はもしよかったらご覧ください。

##コマンド

前回の記事で使用していた、**postsテーブル**を使用して説明していきます。

postsテーブルは、**message**と**likes**の二つのCULUMNがありました。
Twitterでいう、ツイート内容といいねだと思ってください。

###値に制限をつける

テーブルを作成する際に、格納することができるデータに制限を付けることが出来ます。

`message VARCHAR(140) UNIQUE`ですが、`UNIQUE`が追加されています。
この`UNIQUE`ですが、同じ値がすでに存在している時にエラーが発生します。

また、`likes INT CHECK (likes >= 0 AND likes <= 100)`は、
**０以上１００以下**でないとlikesに入れることができないという制限です。

`CHECK`の後に条件式を指定します。
`AND`というのは**〜かつ〜**という意味で、前後の条件を満たしている時しかTRUEになりません。

次に場合ですと、`Thanks`が被っているのでエラーが発生します。

```sql
DROP TABLE IF EXISTS posts;
CREATE TABLE posts (
  message VARCHAR(140) UNIQUE, 
  likes INT CHECK (likes >= 0 AND likes <= 100)
);

INSERT INTO posts (message, likes) VALUES 
  ('Thanks', 12),
  ('Thanks', 4),
  ('Merci', 100);

SELECT * FROM posts;

実行結果
ERROR 1062 (23000) at line 7: Duplicate entry 'Thanks' for key 'message'
```


なので、次のようにしてあげるとエラーが消えてデータを格納することが出来ます。

```sql
DROP TABLE IF EXISTS posts;
CREATE TABLE posts (
  message VARCHAR(140) UNIQUE, 
  likes INT CHECK (likes >= 0 AND likes <= 100)
);

INSERT INTO posts (message, likes) VALUES 
  ('Thanks', 12),
  ('Thank you', 4),
  ('Merci', 100);

SELECT * FROM posts;

実行結果
+-----------+-------+
| message   | likes |
+-----------+-------+
| Thanks    |    12 |
| Thank you |     4 |
| Merci     |   100 |
+-----------+-------+
```

###主キーを設定する
テーブルからレコード（行）を取り出す際に、
そのレコードを一意に識別するためのカラムを設定するのが一般的です。

大抵の場合は`id`という名前でNULLではない整数の連番にします。
**NULL**とは、何も値が入っていない状態を指します。

テーブルのカラムにidを追加するので、
`CREATE TABLE`内にidを追加します。

この時、NULLは許容しないので`id INT NOT NULL`と記述します。
**idはINT型でNULLはNOTですよ！**的な感じです。

また、このidを主キー（プライマリキー）にしたいので、
`PRIMARY KEY (id)`を定義します。

下記の場合では、`(2, 'Arigato', 4)`と`(2, 'Merci', 4)`で
idの値が被っているのでエラーが発生します。

```sql
DROP TABLE IF EXISTS posts;
CREATE TABLE posts (
  id INT NOT NULL,
  message VARCHAR(140), 
  likes INT,
  PRIMARY KEY (id)
);
  
INSERT INTO posts (id, message, likes) VALUES 
  (1, 'Thanks', 12),
  (2, 'Arigato', 4),
  (2, 'Merci', 4);
  
SELECT * FROM posts;

実行結果
ERROR 1136 (21S01) at line 23: Column count doesn't match value count at row 1
```

なので、idを書き換えて再度実行してみます。

```sql
DROP TABLE IF EXISTS posts;
CREATE TABLE posts (
  id INT NOT NULL,
  message VARCHAR(140), 
  likes INT,
  PRIMARY KEY (id)
);
  
INSERT INTO posts (id, message, likes) VALUES 
  (1, 'Thanks', 12),
  (2, 'Arigato', 4),
  (3, 'Merci', 4);
  
SELECT * FROM posts;

実行結果
+----+---------+-------+
| id | message | likes |
+----+---------+-------+
|  1 | Thanks  |    12 |
|  2 | Arigato |     4 |
|  3 | Merci   |     4 |
+----+---------+-------+
```

また、こちらのidですが、自動で振ることも可能です。

自動で振る場合は`id INT NOT NULL AUTO_INCREMENT`とします。

```sql
DROP TABLE IF EXISTS posts;
CREATE TABLE posts (
  id INT NOT NULL AUTO_INCREMENT,
  message VARCHAR(140), 
  likes INT,
  PRIMARY KEY (id)
);
  
INSERT INTO posts (message, likes) VALUES 
  ('Thanks', 12),
  ('Arigato', 4),
  ('Merci', 4);
  
SELECT * FROM posts;

実行結果
+----+---------+-------+
| id | message | likes |
+----+---------+-------+
|  1 | Thanks  |    12 |
|  2 | Arigato |     4 |
|  3 | Merci   |     4 |
+----+---------+-------+
```

こちらの方がidの書き忘れもなく
自動で番号を増やしていってくれるので楽ですね。

###データの抽出

データを抽出する際には**SELECT**を使用します。

今まで`SELECT * FROM posts;`と記述していましたが、
テーブルから一部のデータを抽出することも出来ますし、
条件を付けて抽出することも出来ます。

`SELECT * FROM posts;`は全てのデータを抽出します。

```sql
DROP TABLE IF EXISTS posts;
CREATE TABLE posts (
  id INT NOT NULL AUTO_INCREMENT,
  message VARCHAR(140), 
  likes INT,
  PRIMARY KEY (id)
);

INSERT INTO posts (message, likes) VALUES 
  ('Thanks', 12),
  ('Arigato', 4),
  ('Merci', 4),
  ('Gracias', 15),
  ('Danke', 23); 

SELECT * FROM posts;

実行結果
+----+---------+-------+
| id | message | likes |
+----+---------+-------+
|  1 | Thanks  |    12 |
|  2 | Arigato |     4 |
|  3 | Merci   |     4 |
|  4 | Gracias |    15 |
|  5 | Danke   |    23 |
+----+---------+-------+
```

`SELECT * FROM posts;`を
`SELECT id, message FROM posts;`に変更します。

**id**と**message**をpostsテーブルから抽出します。

```sql
DROP TABLE IF EXISTS posts;
CREATE TABLE posts (
  id INT NOT NULL AUTO_INCREMENT,
  message VARCHAR(140), 
  likes INT,
  PRIMARY KEY (id)
);

INSERT INTO posts (message, likes) VALUES 
  ('Thanks', 12),
  ('Arigato', 4),
  ('Merci', 4),
  ('Gracias', 15),
  ('Danke', 23); 

SELECT id, message FROM posts;

実行結果
+----+---------+
| id | message |
+----+---------+
|  1 | Thanks  |
|  2 | Arigato |
|  3 | Merci   |
|  4 | Gracias |
|  5 | Danke   |
+----+---------+
```


`SELECT * FROM posts;`から
`SELECT * FROM posts WHERE message != 'Danke';`にします。

これは、`message`の文字が`Danke`**ではない**データを抽出します。

なぜ、「ではない」なのかというと、`message != 'Danke'`の通り、
`!=`が使用されているからです。

`!=`は**ノットイコール(〜ではない)**という意味合いになります。

```sql
DROP TABLE IF EXISTS posts;
CREATE TABLE posts (
  id INT NOT NULL AUTO_INCREMENT,
  message VARCHAR(140), 
  likes INT,
  PRIMARY KEY (id)
);

INSERT INTO posts (message, likes) VALUES 
  ('Thanks', 12),
  ('Arigato', 4),
  ('Merci', 4),
  ('Gracias', 15),
  ('Danke', 23); 

SELECT * FROM posts WHERE message != 'Danke';

実行結果
+----+---------+-------+
| id | message | likes |
+----+---------+-------+
|  1 | Thanks  |    12 |
|  2 | Arigato |     4 |
|  3 | Merci   |     4 |
|  4 | Gracias |    15 |
+----+---------+-------+
```


`SELECT * FROM posts;`から
`SELECT * FROM posts WHERE likes >= 10 AND message = 'Thanks';`にします。

`SELECT * FROM posts`の部分で、postsから全てのデータを抽出します。が、
`WHERE likes >= 10 AND message = 'Thanks'`の部分により、
**likesの値が10以上**かつ**messageの文字がThanks**のデータのみになります。

```sql
DROP TABLE IF EXISTS posts;
CREATE TABLE posts (
  id INT NOT NULL AUTO_INCREMENT,
  message VARCHAR(140), 
  likes INT,
  PRIMARY KEY (id)
);

INSERT INTO posts (message, likes) VALUES 
  ('Thanks', 12),
  ('Arigato', 4),
  ('Merci', 4),
  ('Gracias', 15),
  ('Danke', 23); 

SELECT * FROM posts WHERE likes >= 10 AND message = 'Thanks';

実行結果
+----+---------+-------+
| id | message | likes |
+----+---------+-------+
|  1 | Thanks  |    12 |
+----+---------+-------+
```


###LIKEと"%"もしくは"_"で文字列を抽出する

文字列の抽出についてですが、完全一致なら＝を使用すればよかったです。
しかし、一部分一致しているものを抽出したい！という時に`%`や`_`を使います。

`%`で**０文字以上の任意の文字**を、
`_`で**任意の一文字**を表現することが出来ます。

例えば**「ありがとう」を含むデータを抽出してくれ！**という場合は
`%ありがとう%`のように記述します。

何文字かわからないけど、ありがとうの前後に文字がある場合なので`%ありがとう%`とします。

また、**０文字以上の任意の文字列**なので、
文字数だけでないどのような文字でも大丈夫です。

つまり、「ありがとう」という単語さえ入っていれば一致です。

では、実際に**「t」という文字が入っているデータ**を抽出します。


```sql
DROP TABLE IF EXISTS posts;
CREATE TABLE posts (
  id INT NOT NULL AUTO_INCREMENT,
  message VARCHAR(140), 
  likes INT,
  PRIMARY KEY (id)
);

INSERT INTO posts (message, likes) VALUES 
  ('Thank you!', 12),
  ('thanks 100%', 4),
  ('Gracias', 4),
  ('Arigato_gozaimasu', 15),
  ('Arigato! desu', 23);

SELECT * FROM posts WHERE message LIKE '%t%';

実行結果
+----+-------------------+-------+
| id | message           | likes |
+----+-------------------+-------+
|  1 | Thank you!        |    12 |
|  2 | thanks 100%       |     4 |
|  4 | Arigato_gozaimasu |    15 |
|  5 | Arigato! desu     |    23 |
+----+-------------------+-------+
```

どれもtが入っているものです。

次に、**３文字目にYが入っているデータをくれ！**という場合。
`%Y%`としてしまうと、何文字目か分からないけどYが入っているデータが抽出されます。

３文字目という指定があるので、この時は`_`を使用します。
`_`は**任意の一文字**を表現するので`__Y`とすればOKです。

実際に３文字目にaが入っているデータを抽出します。

```sql
DROP TABLE IF EXISTS posts;
CREATE TABLE posts (
  id INT NOT NULL AUTO_INCREMENT,
  message VARCHAR(140), 
  likes INT,
  PRIMARY KEY (id)
);

INSERT INTO posts (message, likes) VALUES 
  ('Thank you!', 12),
  ('thanks 100%', 4),
  ('Gracias', 4),
  ('Arigato_gozaimasu', 15),
  ('Arigato! desu', 23);

SELECT * FROM posts WHERE message LIKE '__a%';

実行結果
+----+-------------+-------+
| id | message     | likes |
+----+-------------+-------+
|  1 | Thank you!  |    12 |
|  2 | thanks 100% |     4 |
|  3 | Gracias     |     4 |
+----+-------------+-------+
```

無事抽出することが出来ました！

ここで一つ疑問に思うのが、
`thanks 100%`や`Arigato_gozaimasu `のような文字列に対して、
`%`や`_`で条件を絞る場合はどうすればいいの？ということです。

`%%%`のように記述しても全ての値を抽出するだけです。
ではどうするのかというわけですが、`%\%%`のように記述します。

**バックスラッシュ**を付けることによって`%`が文字という扱いになります。
バックスラッシュの打ち方は、Macなら`option + ¥キー`です。
Windowsは`¥キー`だけで平気かな？

実際に記述してみます。

```sql
DROP TABLE IF EXISTS posts;
CREATE TABLE posts (
  id INT NOT NULL AUTO_INCREMENT,
  message VARCHAR(140), 
  likes INT,
  PRIMARY KEY (id)
);

INSERT INTO posts (message, likes) VALUES 
  ('Thank you!', 12),
  ('thanks 100%', 4),
  ('Gracias', 4),
  ('Arigato_gozaimasu', 15),
  ('Arigato! desu', 23);

SELECT * FROM posts WHERE message LIKE '%\%%';

実行結果
+----+-------------+-------+
| id | message     | likes |
+----+-------------+-------+
|  2 | thanks 100% |     4 |
+----+-------------+-------+
```

`_`も同様の方法で行うことが出来ます。

###抽出結果を並び替える

抽出結果をlikes（いいね）の数で並び替えたりすることも可能です。

並び替えを行うには`ORDER BY`を使用します。
また、並び替えた後に`DESC`を使用し降順か昇順かを変えることも可能です。

```sql
DROP TABLE IF EXISTS posts;
CREATE TABLE posts (
  id INT NOT NULL AUTO_INCREMENT,
  message VARCHAR(140), 
  likes INT,
  PRIMARY KEY (id)
);

INSERT INTO posts (message, likes) VALUES 
  ('Thanks', 12),
  ('Merci', 4),
  ('Arigato', 4),
  ('Gracias', 15),
  ('Danke', 8);

SELECT * FROM posts ORDER BY likes;
SELECT * FROM posts ORDER BY likes DESC;

実行結果
+----+---------+-------+
| id | message | likes |
+----+---------+-------+
|  2 | Merci   |     4 |
|  3 | Arigato |     4 |
|  5 | Danke   |     8 |
|  1 | Thanks  |    12 |
|  4 | Gracias |    15 |
+----+---------+-------+
+----+---------+-------+
| id | message | likes |
+----+---------+-------+
|  4 | Gracias |    15 |
|  1 | Thanks  |    12 |
|  5 | Danke   |     8 |
|  2 | Merci   |     4 |
|  3 | Arigato |     4 |
+----+---------+-------+
```

降順と昇順が切り替わっているのがわかります。

また、`DESC`を付けた場合、
同じlikesの値で４番目に`Merci`、５番目に`Arigato`がきています。

likesの値は同じなので、その場合はmessageでも降順と昇順を変えたい！
という場合は少なくないと思います。

その場合は下記のように行います。

```sql
DROP TABLE IF EXISTS posts;
CREATE TABLE posts (
  id INT NOT NULL AUTO_INCREMENT,
  message VARCHAR(140), 
  likes INT,
  PRIMARY KEY (id)
);

INSERT INTO posts (message, likes) VALUES 
  ('Thanks', 12),
  ('Merci', 4),
  ('Arigato', 4),
  ('Gracias', 15),
  ('Danke', 8);
  
SELECT * FROM posts ORDER BY likes DESC, message;

実行結果
+----+---------+-------+
| id | message | likes |
+----+---------+-------+
|  4 | Gracias |    15 |
|  1 | Thanks  |    12 |
|  5 | Danke   |     8 |
|  3 | Arigato |     4 |
|  2 | Merci   |     4 |
+----+---------+-------+
```


これで綺麗に並び替えることが出来ました。

次に、likesの数が大きい順で上から３レコード（上位3位）分を取得したい場合です。
その場合は`LIMIT`を使用します。

```sql
DROP TABLE IF EXISTS posts;
CREATE TABLE posts (
  id INT NOT NULL AUTO_INCREMENT,
  message VARCHAR(140), 
  likes INT,
  PRIMARY KEY (id)
);

INSERT INTO posts (message, likes) VALUES 
  ('Thanks', 12),
  ('Merci', 4),
  ('Arigato', 4),
  ('Gracias', 15),
  ('Danke', 8);

SELECT * FROM posts ORDER BY likes DESC, likes LIMIT 3;

実行結果
+----+---------+-------+
| id | message | likes |
+----+---------+-------+
|  4 | Gracias |    15 |
|  1 | Thanks  |    12 |
|  5 | Danke   |     8 |
+----+---------+-------+
```

あまりないかもしれませんが、
上から３番目のレコードから３レコード分取得したい場合があったとします。

つまり、下記の場合なら**Danke**から**Merci**までです。

```
+----+---------+-------+
| id | message | likes |
+----+---------+-------+
|  4 | Gracias |    15 |
|  1 | Thanks  |    12 |
|  5 | Danke   |     8 |
|  3 | Arigato |     4 |
|  2 | Merci   |     4 |
+----+---------+-------+
```

その場合は`OFFSET`を使用します。

```sql
DROP TABLE IF EXISTS posts;
CREATE TABLE posts (
  id INT NOT NULL AUTO_INCREMENT,
  message VARCHAR(140), 
  likes INT,
  PRIMARY KEY (id)
);

INSERT INTO posts (message, likes) VALUES 
  ('Thanks', 12),
  ('Merci', 4),
  ('Arigato', 4),
  ('Gracias', 15),
  ('Danke', 8);
  
SELECT * FROM posts ORDER BY likes DESC, message LIMIT 3 OFFSET 2;

実行結果
+----+---------+-------+
| id | message | likes |
+----+---------+-------+
|  5 | Danke   |     8 |
|  3 | Arigato |     4 |
|  2 | Merci   |     4 |
+----+---------+-------+
```

上手く抽出が出来ていることがわかります。

ここで疑問に思う人がいると思うのですが、`OFFSET 2`だと、
２番目から抽出してしまうのではないか？というところです。

これは、配列などと同じで、
１番目を**０**、２番目を**１**、３番目を**２**と数えます。

なので、**OFFSET 2**は上から３番目ということになります。

###レコードの更新を行う

Twitterでもユーザの名前が変わったり、
プロフィール内容が変わったりとよくデータを変更します。

なのでレコードの更新方法について説明します。

レコードの更新には`UPDATE`を使用します。
UPDATEは下記のように記述します。

```
UPDATE <テーブル名> SET <カラム(複数指定可)> WHERE <条件（省略可）>;
```

なお、UPDATEは長くなることが多いので改行して書くことをおすすめします。

```
UPDATE
  <テーブル名> 
SET
  <カラム(複数指定可)> 
WHERE
  <条件（省略可）>;
```

では実際のテーブルを更新してみたいと思います。

今回は、`likesの値を＋５`と`messageの文字列を大文字にする`を行います。
しかし、WHEREでlikesの値が１０以上のレコードのみです。

文字列を全て大文字にするのには`UPPER()`関数を使用します。

```sql
DROP TABLE IF EXISTS posts;
CREATE TABLE posts (
  id INT NOT NULL AUTO_INCREMENT,
  message VARCHAR(140), 
  likes INT,
  PRIMARY KEY (id)
);

INSERT INTO posts (message, likes) VALUES 
  ('Thanks', 12),
  ('Merci', 4),
  ('Arigato', 4),
  ('Gracias', 15),
  ('Danke', 8);
 
UPDATE 
  posts 
SET 
  likes = likes + 5,
  message = UPPER(message)
WHERE
  likes >= 10;
SELECT * FROM posts;

実行結果
+----+---------+-------+
| id | message | likes |
+----+---------+-------+
|  1 | THANKS  |    17 |
|  2 | Merci   |     4 |
|  3 | Arigato |     4 |
|  4 | GRACIAS |    20 |
|  5 | Danke   |     8 |
+----+---------+-------+
```

###レコードを削除する

ツイートを削除した際にそのツイートのデータを削除するように、
レコードの削除処理もよく行われます。

レコードの削除を行うには`DELETE`を使用します。

全てのレコードを削除する場合は、`DELETE FROM <テーブル名>;`ですが
全て削除することはあまりないと思うので条件を付けたい時があると思います。

条件を付ける場合は`UPDATE`の時と同じで後ろに`WHERE`を付けます。

下記の場合は、likesが１０以下のレコードを全て削除しています。

```sql
DROP TABLE IF EXISTS posts;
CREATE TABLE posts (
  id INT NOT NULL AUTO_INCREMENT,
  message VARCHAR(140), 
  likes INT,
  PRIMARY KEY (id)
);

INSERT INTO posts (message, likes) VALUES 
  ('Thanks', 12),
  ('Merci', 4),
  ('Arigato', 4),
  ('Gracias', 15),
  ('Danke', 8); 

DELETE FROM posts WHERE likes < 10;
SELECT * FROM posts;

実行結果
+----+---------+-------+
| id | message | likes |
+----+---------+-------+
|  1 | Thanks  |    12 |
|  4 | Gracias |    15 |
+----+---------+-------+
```

実行結果を見ると、５つあったレコードの内３つが削除され、id１とid４が残りましたが、
この状態の時にデータを追加した時のidは２なのか６なのかどちらだと思いますか？

ということでレコードを追加してみたいと思います。

レコードの追加は`INSERT INTO`です。

```sql
DROP TABLE IF EXISTS posts;
CREATE TABLE posts (
  id INT NOT NULL AUTO_INCREMENT,
  message VARCHAR(140), 
  likes INT,
  PRIMARY KEY (id)
);

INSERT INTO posts (message, likes) VALUES 
  ('Thanks', 12),
  ('Merci', 4),
  ('Arigato', 4),
  ('Gracias', 15),
  ('Danke', 8); 
  
DELETE FROM posts WHERE likes < 10;
INSERT INTO posts (message, likes) VALUES ('Xie Xie', 10);

SELECT * FROM posts;

実行結果
+----+---------+-------+
| id | message | likes |
+----+---------+-------+
|  1 | Thanks  |    12 |
|  4 | Gracias |    15 |
|  6 | Xie Xie |    10 |
+----+---------+-------+
```

答えは６で追加されました。

２・３・５がもったいない！と思います。
再度しっかりとidを振り直したい場合はテーブルを削除するしかありません。

テーブルの削除は`DROP`で行えますが、
削除した後に再作成する`TRUNCATE`を使うこともできます。

```sql
DROP TABLE IF EXISTS posts;
CREATE TABLE posts (
  id INT NOT NULL AUTO_INCREMENT,
  message VARCHAR(140), 
  likes INT,
  PRIMARY KEY (id)
);

INSERT INTO posts (message, likes) VALUES 
  ('Thanks', 12),
  ('Merci', 4),
  ('Arigato', 4),
  ('Gracias', 15),
  ('Danke', 8); 
  
TRUNCATE TABLE posts;
INSERT INTO posts (message, likes) VALUES ('Xie Xie', 10);

SELECT * FROM posts;

実行結果
+----+---------+-------+
| id | message | likes |
+----+---------+-------+
|  1 | Xie Xie |    10 |
+----+---------+-------+
```

テーブルが再作成されて、idが１番からふり直されていることが確認出来ました！


###作成、更新日時を自動で設定する

レコードが作成された日時と、レコードが更新された日時を自動で設定します。

テーブルのカラムに`created DATETIME DEFAULT NOW()`と
`updated DATETIME DEFAULT NOW() ON UPDATE NOW()`を記述します。

`DEFAULT`というのは、そのままの意味でデフォルトの値です。

`INSERT INTO`の際にVALUESで値を指定していますが、
DEFAULTがついているカラムはVALUESで値を指定しなかった場合に**デフォルト値**が入ります。

今回はそのデフォルト値を`NOW()`として現在時刻を入れるようにしています。

次に、`ON UPDATE NOW()`ですが、
レコードの更新を行う際の`UPDATE`を使用した時に`NOW()`を自動で入れてくれます。

つまり、`updated`の値は`UPDATE`を行うたびに
自動で更新されていくという仕組みになります。

`SELECT id, created, updated FROM posts;`で、
現在のテーブルの**id, 作成日, 更新日**の値を取得しています。

`SELECT SLEEP(3);`は処理を３秒間止めるコマンドです。

３行後に`UPDATE posts SET likes = 100 WHERE id = 1;`を実行します。
**id**が**１**のレコードに対してlikesの値を100にしています。



```sql
DROP TABLE IF EXISTS posts;
CREATE TABLE posts (
  id INT NOT NULL AUTO_INCREMENT,
  message VARCHAR(140), 
  likes INT,
  created DATETIME DEFAULT NOW(),
  updated DATETIME DEFAULT NOW() ON UPDATE NOW(),
  PRIMARY KEY (id)
);

INSERT INTO posts (message, likes) VALUES 
  ('Thanks', 12),
  ('Merci', 4),
  ('Arigato', 4),
  ('Gracias', 15),
  ('Danke', 8);
  
SELECT id, created, updated FROM posts;
SELECT SLEEP(3);
UPDATE posts SET likes = 100 WHERE id = 1;

SELECT id, created, updated FROM posts;

実行結果
+----+---------------------+---------------------+
|  1 | 2021-03-20 20:05:34 | 2021-03-20 20:05:34 |
|  2 | 2021-03-20 20:05:34 | 2021-03-20 20:05:34 |
|  3 | 2021-03-20 20:05:34 | 2021-03-20 20:05:34 |
|  4 | 2021-03-20 20:05:34 | 2021-03-20 20:05:34 |
|  5 | 2021-03-20 20:05:34 | 2021-03-20 20:05:34 |
+----+---------------------+---------------------+
+----------+
| SLEEP(3) |
+----------+
|        0 |
+----------+
+----+---------------------+---------------------+
| id | created             | updated             |
+----+---------------------+---------------------+
|  1 | 2021-03-20 20:05:34 | 2021-03-20 20:05:37 |
|  2 | 2021-03-20 20:05:34 | 2021-03-20 20:05:34 |
|  3 | 2021-03-20 20:05:34 | 2021-03-20 20:05:34 |
|  4 | 2021-03-20 20:05:34 | 2021-03-20 20:05:34 |
|  5 | 2021-03-20 20:05:34 | 2021-03-20 20:05:34 |
+----+---------------------+---------------------+
```

実行結果からわかる通り、
id１のみupdatedが更新されています。

###テーブルの設計を変更する

一度テーブルを作成した後に、
「カラムを追加したい！」、「カラムの名前を変えたい！」、「テーブルの名前を変えたい！」
なんて時があるかもしれません。

その時のコマンドを紹介します。

**・カラムを追加する時**

カラムを追加する時は下記のコマンドで行います。

```
ALTER TABLE <テーブル名> ADD <カラム名> <型>;
```

場所を指定することも出来ます。

```
ALTER TABLE <テーブル名> ADD <カラム名> <型> AFTER <カラム名>;
```

では、実際にやってみます。

**author**というカラムを**VARCHAR(255)型**で追加します。

```sql
DROP TABLE IF EXISTS posts;
CREATE TABLE posts (
  id INT NOT NULL AUTO_INCREMENT,
  message VARCHAR(140), 
  likes INT,
  PRIMARY KEY (id)
);

INSERT INTO posts (message, likes) VALUES 
  ('Thanks', 12),
  ('Merci', 4),
  ('Arigato', 4),
  ('Gracias', 15),
  ('Danke', 8);

ALTER TABLE posts ADD author VARCHAR(255);
DESC posts;

実行結果
+---------+--------------+------+-----+---------+----------------+
| Field   | Type         | Null | Key | Default | Extra          |
+---------+--------------+------+-----+---------+----------------+
| id      | int(11)      | NO   | PRI | NULL    | auto_increment |
| message | varchar(140) | YES  |     | NULL    |                |
| likes   | int(11)      | YES  |     | NULL    |                |
| author  | varchar(255) | YES  |     | NULL    |                |
+---------+--------------+------+-----+---------+----------------+
```

authorが追加されているのがわかります。

idの下に追加したい場合は下記のようにします。

```sql
ALTER TABLE posts ADD author VARCHAR(255) AFTER id;
```


**・カラム名を変えたい時**

カラム名を変えたい時は下記のコマンドを記述します。

```
ALTER TABLE <テーブル名> CHANGE <変更前カラム名> <変更後カラム名> <型>;
```

実際に記述すると下記のようになります。

```sql
DROP TABLE IF EXISTS posts;
CREATE TABLE posts (
  id INT NOT NULL AUTO_INCREMENT,
  message VARCHAR(140), 
  likes INT,
  PRIMARY KEY (id)
);

INSERT INTO posts (message, likes) VALUES 
  ('Thanks', 12),
  ('Merci', 4),
  ('Arigato', 4),
  ('Gracias', 15),
  ('Danke', 8);

ALTER TABLE posts CHANGE likes points INT;
DESC posts;

実行結果
+---------+--------------+------+-----+---------+----------------+
| Field   | Type         | Null | Key | Default | Extra          |
+---------+--------------+------+-----+---------+----------------+
| id      | int(11)      | NO   | PRI | NULL    | auto_increment |
| message | varchar(140) | YES  |     | NULL    |                |
| points  | int(11)      | YES  |     | NULL    |                |
+---------+--------------+------+-----+---------+----------------+
```

**likes**が**point**に変わっているのがわかります。

**・テーブル名を変える時**

テーブル名を変える時は下記のコマンドを記述します。

```
ALTER TABLE <変更前テーブル名> RENAME <変更後テーブル名>;
```

変更後のテーブルが存在しているとエラーになりますので要注意。

実際に記述すると下記のようになります。

```sql
DROP TABLE IF EXISTS posts;
CREATE TABLE posts (
  id INT NOT NULL AUTO_INCREMENT,
  message VARCHAR(140), 
  likes INT,
  PRIMARY KEY (id)
);

INSERT INTO posts (message, likes) VALUES 
  ('Thanks', 12),
  ('Merci', 4),
  ('Arigato', 4),
  ('Gracias', 15),
  ('Danke', 8);

ALTER TABLE posts RENAME messages;
SHOW TABLES;

実行結果
+-----------------+
| Tables_in_myapp |
+-----------------+
| messages        |
+-----------------+
```

**postsテーブル**が**messageテーブル**に変更しているのがわかります。

#さいごに

このくらい覚えておけばそれなりに操作することができるのではないかなと思います。
ただ、まだまだできることはたくさんあるのでぜひ調べてみてください！

私も学習しながら役に立つ内容があったら共有しようと思います！

以上、最後までご覧いただきありがとうございました。