「スッキリわかる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%AC3%E7%89%88-%E3%83%89%E3%83%AA%E3%83%AB256%E5%95%8F%E4%BB%98%E3%81%8D-%E3%82%B9%E3%83%83%E3%82%AD%E3%83%AA%E3%82%8F%E3%81%8B%E3%82%8B%E5%85%A5%E9%96%80%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA-%E4%B8%AD%E5%B1%B1/dp/4295013390/ref=sr_1_1?adgrpid=51361540737&hvadid=658841395612&hvdev=c&hvlocphy=9162130&hvnetw=g&hvqmt=e&hvrand=16054762148403698574&hvtargid=kwd-333587866250&hydadcr=27265_14678545&jp-ad-ap=0&keywords=%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&qid=1689765619&sr=8-1) を読んだので、個人的に気になったことなどをまとめてます。


# 学んだこと

### 集合演算子
#### 和集合
縦にくっつける
```sql
SELECT column FROM table1
UNION
SELECT column FROM table2
```
#### 差集合
```sql
SELECT column FROM table1
EXCEPT
SELECT column FROM table2
```
#### 積集合
```sql
SELECT column FROM table1
INTERSECT 
SELECT column FROM table2
```

### NULLでない値を返す
引数のうち、最初に現れたNULLでない引数を返す。
```sql
COALESCE('A', 'B', 'C') /* 結果：A */
COALESCE(NULL, 'B', 'C') /* 結果：B */
COALESCE(NULL, 'B', NULL) /* 結果：B */
```

NULLでない場合は値を、NULLの場合は他の値を返す時に使う。
```sql
SELECT COALESCE(column, 'columnはNULLです')
FROM table
```

### トランザクション管理
```sql
BEGIN;
処理1
処理2
COMMIT;
```

### トランザクション処理における副作用
<dl>
  <dt>ダーティーリード</dt>
  <dd>まだコミットされていない未確定の変更を、他の人が読めてしまう。</dd>
  <dt>ノンリピータブルリード</dt>
  <dd>SELECT文を実行した後、他の人がUPDATE文でデータを書き換えると、次にSELECTした際に結果が異なってしまう</dd>
  <dt>ファントムリード</dt>
  <dd>2回のSELECT文の間に、他の人がINSERT文で行を追加すると、最初と次のSELECTで取得する結果の行数が変わってしまう</dd>
</dl>

### トランザクション分離レベル
<table>
    <thead>
        <tr>
            <th>分離レベル</th>
            <th>ダーティーリード</th>
            <th>ノンリピータブルリード</th>
            <th>ファントムリード</th>
        </tr>
    </thead>
    <tr>
        <td>READ UNCOMMITTED</td> 
        <td>恐れあり</td>
        <td>恐れあり</td> 
        <td>恐れあり</td>
    </tr>
    <tr>
        <td>READ COMMITTED</td> 
        <td>発生しない</td>
        <td>恐れあり</td> 
        <td>恐れあり</td>
    </tr>
    <tr>
        <td>REPEATABLE READ</td> 
        <td>発生しない</td>
        <td>発生しない</td> 
        <td>恐れあり</td>
    </tr>
    <tr>
        <td>SERIALIZABLE</td> 
        <td>発生しない</td>
        <td>発生しない</td> 
        <td>発生しない</td>
    </tr>
</table>
多くのDBMSでは、デフォルトでREAD COMMITTEDで動作している。

### トランザクション分離レベルの指定
```sql
SET TRANSACTION ISOLATION LEVEL 分離レベル
SET CURRENT ISOLATION 分離レベル
```

### 明示的な行ロック
```sql
SELECT column FROM table FOR UPDATE;
```

### 明示的な表ロック
```sql
LOCK TABLE table IN モード名 MODE
```

### 権限付与・権限はく奪
```sql
/* 権限付与 */
GRANT 権限名 TO ユーザ名

/* 権限はく奪 */
REVOKE 権限名 FROM ユーザ名
```

### Create時の制約
<dl>
  <dt>NOT NULL</dt>
  <dd>NULLを許可しない。DEFALUTと組み合わせて利用されることがほとんど。</dd>
  <dt>UNIQUE</dt>
  <dd>内容が重複してはいけない。</dd>
  <dt>CHECK</dt>
  <dd>CHECKのあとの条件式が真になる値だけ格納する。</dd>
  <dt>PRIMARY KEY</dt>
  <dd>NULLも重複も許可しない</dd>
  <dt>REFERENCES</dt>
  <dd>外部キー制約。<code>REFERENCES 参照先テーブル名 (参照先列名)</code>で定義する。<br>
    </dd>
</dl>

外部キー制約は最後にまとめて定義できる。
```sql
CREATE TABLE table (
    …
    FOREIGN KEY(参照元列名)
        REFERENCES 参照先テーブル名 (参照先列名)
)
```

### インデックス
- インデックスは指定した列に対して作られる。
- 複数列をひとつのインデックスとする複合インデックスも作成可能
- メリット
    - インデックスが存在する列に対して検索が行われると、高速になる場合が多い
- デメリット
    - インデックを作成するとディスク容量を消費する
    - データが更新されるとインデックスも書き変える必要があるため、INSERT, UPDATE, DELETEのオーバヘッドが増える。

```sql
/* インデックス作成 */
CREATE INDEX インデックス名 ON テーブル名(列名)

/* インデックス削除 */
DROP INDEX インデックス名
```


# 参考文献

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%AC3%E7%89%88-%E3%83%89%E3%83%AA%E3%83%AB256%E5%95%8F%E4%BB%98%E3%81%8D-%E3%82%B9%E3%83%83%E3%82%AD%E3%83%AA%E3%82%8F%E3%81%8B%E3%82%8B%E5%85%A5%E9%96%80%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA-%E4%B8%AD%E5%B1%B1/dp/4295013390/ref=sr_1_1?adgrpid=51361540737&hvadid=658841395612&hvdev=c&hvlocphy=9162130&hvnetw=g&hvqmt=e&hvrand=16054762148403698574&hvtargid=kwd-333587866250&hydadcr=27265_14678545&jp-ad-ap=0&keywords=%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&qid=1689765619&sr=8-1