[SQL]SQL入門　- テーブルの作成 -

# はじめに
こちらは[スッキリわかるSQL入門](https://www.amazon.co.jp/%E3%82%B9%E3%83%83%E3%82%AD%E3%83%AA%E3%82%8F%E3%81%8B%E3%82%8BSQL%E5%85%A5%E9%96%80-%E7%AC%AC2%E7%89%88-%E3%83%89%E3%83%AA%E3%83%AB222%E5%95%8F%E4%BB%98%E3%81%8D-%E3%82%B9%E3%83%83%E3%82%AD%E3%83%AA%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA-%E4%B8%AD%E5%B1%B1%E6%B8%85%E5%96%AC/dp/4295005096)をまとめた記事となります。
今回は「テーブルの作成」についてです。
プログラミング初学者向けの内容となっていますので、お気づきの点があれば、コメントの方をよろしくお願いします。

# SQL4種類の命令（DML,TCL,DDL,DCL）
データベースを利用する際にSQLでは様々な命令が出せます。

**立場①　データベースにデータの出し入れを指示する立場**
**DML:Data Mnipulation Language**
データ操作言語：データの格納や取り出し、更新、削除などの命令
SELECT,INSERT,UPDATE,DELETE
EXPLAN,LOCKTABLE

**TCL:Transaction Control Language**
トランザクション制御言語：トランザクションの開始や終了の命令
COMMIT,ROLLBACK,SET TRANSACTION,SAVEPOINT

**立場②　立場①の人が、効率よく、安全にデータの出し入れができるよう必要なテーブル準備や各種設定を指示する立場**
**DDL:Data Definition Language**
データ定義言語：テーブルなどの作成や削除、各種設定などの命令
CREATE,ALTER,DROP,TRUNCATE

**DCL:Data Control Language**
データ制御言語：DMLやDDLの利用に関する許可や禁止を設定する命令
GRANT,REVOKE

# GRANT文とREVOKE文

```sql:
GRANT 権限名 TO ユーザー名 -- 権限を付与する
REVOKE 権限名 FROM ユーザー名 -- 権限を剥奪する
```

これらは立場②の中でも特にデータベースの全権を管理する、データベース管理者（DBA:Database Administrator）の立場の人だけが使う命令。
DBMS製品によって構文や位置づけが大きく異なる。
# テーブル作成（基本的な構文）
### CREATE TABLE文
作成したいテーブルの名前、テーブルを構成する列と型の一覧を指定し、テーブルを定義します。

```sql:テーブルの作成
CREATE TABLE テーブル名(
列名1 列1の型名,
列名2 列2の型名,
:
列名X 列Xの型名
)
```

```sql:家計簿テーブルを作成
CREATE TABLE 家計簿 (日付 DATE, 費目ID INTEGER, メモ VARCHAR(100),入金額 INTEGER,出金額 INTEGER);
```


### デフォルト値の設定

```sql:家計テーブルに対する行の追加
INSERT INTO 家計簿 (日付, メモ, 出金額) VALUES('2018-04-12', '詳細は後で', 60000);
```

結果: 「費目ID」と「入金額」の列の内容は、次の結果表にあるようにNULLとなります。
![スクリーンショット 2021-07-21 19.58.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1050283/3cb94cf7-3040-f6db-6153-994b6ab838d7.png)
INSERT文で具体的な値を指定しなかった場合に、NULLが格納されてしまいますが、特定のデフォルト値（初期値）を格納することも可能です。
テーブルを作成する際に、デフォルト値を決めておくことで、「特に指定しなければ入金額には0が格納される」というような設定を行うことが可能です。
そのためにはDFAULTキーワードを指定します。

```sql:デフォルト値の指定を含むテーブルの作成
CREATE TABLE テーブル名(
列名 型名 DEFAULT デフォルト値,
:
)
```

```sql:家計簿テーブルを作成する（デフォルト値を活用）
CREATE TABLE 家計簿(
日付 DATE, 
費目ID INTEGER, 
メモ VARCHAR(100) DEFAULT '不明', 
入金額 INTEGER DEFAULT 0, 
出金額 INTEGER DEFAULT 0
)
```
# テーブルの削除
### DROP TABLE文
テーブル自体を削除する構文
DBMS製品によってはロールバックできず、一度実行してしまうと取り消しすることができなくなる場合があるので、バックアップしておくなど安全への配慮もしておく。

```sql:テーブルの削除（基本的な構文）
DROP TABLE テーブル名
```

家計簿テーブルを削除する場合
![スクリーンショット 2021-07-21 23.26.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1050283/b72e1b84-2d17-28f8-128a-99c26f9474d1.png)

### TRUNCATE TABLE文
テーブル全行を削除する場合に利用することがある
・ DELETEはWHERE句で指定した行だけ削除できるが、TRUNCATEは必ず全行を削除する。
・ DELETEはDMLだが、TRUNCATEはDDLに属する命令である。
・ DELETEはロールバックに備えて記録を残しながら仮削除していくが、TRUNCATEは記録を残さずに行を削除する（よってロールバックできない）。
・ DELETEは記録を残す為低速だが、TRUNCATEは高速。

```sql:テーブルの全行を削除する場合
TRUNCATE TABLE 家計簿     -- 家計簿テーブルの全行を削除 --
```
結果
![スクリーンショット 2021-07-21 23.24.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1050283/c8588e60-5fd5-3d13-55a9-727083d56a5c.png)

# テーブル定義の変更
### ALTER TABLE文

```sql:テーブル定義の変更
-- 列の追加
ALTER TABLE テーブル名 ADD 列名 型 制約
-- 列の削除
ALTER TABLE テーブル名　DROP 列名 型 制約
```

```sql:列の追加と削除
-- 追加する時
ALTER TABLE 家計簿 ADD 関連日 DATE;
-- 削除する時
ALTER TABLE 家計簿 DROP 関連日;
```

# 制約
DBMSは**制約（constraint）**という仕組みを備えており、予期しない値を格納できないように制限をかけることで、人為的ミスによるデータ破壊の可能性を減らすことができる。

### 基本的な３つの制約

### NOT NULL 制約
NULLの格納を防ぐことができる。
デフォルト値が設定されていればエラーにならない。

### UNIQUE 制約
重複した値の格納を防ぐことができる。

### CHECK 制約
格納しようとする値が妥当かどうかをチェックできる。

```sql:基本的な3つの制約を活用
CREATE TABLE 家計簿(
日付 DATE NOT NULL, -- NOT NULL制約
費目ID INTEGER,
メモ VARCHAR(100) DEFAULT '不明' NOT NULL,　-- NOT NULL制約
入金額 INTEGER DEFAULT 0 CHECK( 入金額 >= 0), -- CHECK制約
出金額 INTEGER DEFAULT 0 CHECK( 出金額 >= 0) -- CHECK制約
);
CREATE TABLE 費目(
ID INTEGER,
名前 VARCHAR(40) UNIQUE -- UNIQUE制約
);
```

### 主キー制約
主キーとして取り扱いたい列には、主キー制約を設定する。

```sql:主キー制約の指定(1)
CREATE TABLE 費目(
ID INTEGER PRIMARY KEY,
名前 VARCHAR(40) UNIQUE
)
```

また、以下のように記載して複合主キーの指定も可能。

```sql:主キー制約の指定(2)
CREATE TABLE 費目(
ID INTEGER PRIMARY KEY,
名前 VARCHAR(40) UNIQUE,
PRIMARY KEY(ID,名前)
)
```

# 外部キーと参照整合性
データの更新や削除によって外部キーによる参照整合性が崩れることがないように、外部キー制約を設定する。
参照整合性・・・外部キーが指し示す先にきちんと行が存在してリレーションシップが成立していること

その際は以下のようにREFERENCESを使うと、参照整合性が崩れるようなデータ操作をしようとした場合にエラーを発生させ強制的に処理を中断させます。

```sql:外部キー制約の指定１
CREATE TABLE テーブル名(
列名 型 REFERENCES 参照先テーブル名(参照先列名)
)
```

```sql:外部キー制約の指定
CREATE TABLES 家計簿(
日付 DATE NOT NULL,
費目ID INTEGER REFERENCES 費目(ID), -- 外部キー制約
メモ VARCHAR(100) DEFAULT '不明' NOT NULL,
入金額 INTEGER DEFAULT 0 CHECK(入金額>=0),
出金額 INTEGER DEFAULT 0 CHECK(出金額>=0)
)
```

以下の構文を用いる場合の家計簿テーブルの例では、費目IDの列定義には制約を記述しない代わりに、最後に「FOREIGN KEY(費目ID)REFERENCES費目(ID)」という記述を加えることになるでしょう。

```sql:外部キー制約の指定2
CREATE TABLE テーブル名(
FOREIGN KEY (参照元列名) REFERENCES 参照先テーブル名(参照先列名)
)
```

# まとめ
・４種類のSQL命令（DML,TCL,DDL,DCL）
・テーブルの作成（CREATE TABLE文）と削除（DROP TABLE文）
・テーブル作成時に各列に制約を設定し、予期しない値が格納されないようにすることができる。また、参照整合性が崩れないように外部キーを設定する。

# メンバー記事
[【SQL】トランザクションをマスターしよう！](https://qiita.com/Issei_401/items/fe8725e716c868c2bdc0)
[【SQL】SQL文を使って対象をロックする方法](https://qiita.com/Issei_401/items/908bd42c2e512a6f81c9)
[SQLのまとめ③(インデックスについて)](https://qiita.com/akihiro-cmd/items/5c702789cac62dbcd39f)
[【SQL書籍勉強会】テーブル設計](https://qiita.com/vit_udon_husqy/items/9ed675c4feb4ff0d0c28)