SQLの基礎文法のアウトプット

#概要
本記事はRDBMS（リレーショナルデータベース管理システム）を操作するための共通言語であるSQLの基礎について学習したことをアウトプットとしてまとめております。

#はじめに
###データベースとは
データベースとは、データ形式をあらかじめ定義して管理することができるファイル形式のことを指します。データベースのモデルには、リレーショナルデータベース、ツリー型データベース、ネットワーク型データベースなどがあります。
上記であげたモデルのうち、ネットワーク型やツリー型は、データベース構造の設計が難しく汎用性もないといったデメリットがあるため、現在ではあまり利用されておらず、リレーショナルデータベースが一般的に利用されています。

###リレーショナルデータベースとは
リレーショナルデータベースとは、データを行と列からなる表形式で表し、複数の表に関連付けを結ぶことができるデータベースのモデルです。リレーショナルデータベースは構造を理解しやすいことなどからよく利用されています。
今回は、このリレーショナルデータベースを操作するためのSQLについて見ていきます。

#第１章　SQLによるデータ検索（基礎）

##基本的なSELECT文
SELECT文は、データベースに登録されている表(table)や表内の特定の列(column)に対して問い合わせることができます。

```ruby
SELECT [column名] FROM [table名];
```

全ての列(column)を取り出したいときはSELECTの後に'＊'を指定します。

```ruby
SELECT * FROM [table名];
```

同じ列に重複するデータがあり、重複データの省略を行いたい場合はSELECTの後にDISTINCTキーワードを指定します。

```ruby
SELECT distinct [column名] FROM [table名];
```

##WHERE句を使った条件付き検索
WHERE句を使うと、表から条件を満たす行(row)のみに問い合わせを行うことができます。WHERE句の後には、どのような条件で問い合わせを行いたいか指定します。

```ruby
SELECT * FROM [table名] WHERE [column名 演算子 値];
#値が文字列の場合は''をつけ忘れないように注意
```
問い合わせを行うための演算子にはどのようなものがあるか見ていきましょう。

###1. 比較述語（比較演算子）
比較述語は列(column)のデータと値を比較し、条件に一致した場合、TRUEを返します。TRUEが返された行(row)は問い合わせの対象となります。
比較演算子のを使った条件指定には以下のものがあります。

| 比較演算子| 条件 |
|:-:|:-:|
|  = |  列(column)のデータと値が等しいか否かを比較します。 |
|  >  |   列(column)のデータが値より大きいか否かを比較します。 |
|  <|   列(column)のデータが値より小さいか否かを比較します。 |
|   >= |   列(column)のデータが値以上か否かを比較します。 |
|   <= |  列(column)のデータが値以下か否かを比較します。  |
| <>  |   列(column)のデータと値が等しくないか否かを比較します。 |


###2. BETWEEN述語
BETWEEN述語は列(column)のデータが２つの値の範囲内である場合にTRUEを返します。TRUEが返された行(row)は問い合わせの対象となります。
WHERE句の後に比較対象としたいcolumn名、その後ろにBETWEENキーワードを指定し、範囲の開始となる値と範囲の終了となる値の間にANDキーワードを記述します。
範囲の開始となる値を左に、範囲の終了となる値を右に記述します。

```ruby
SELECT * FROM [table名] WHERE [column名] BETWEEN 開始値 AND 終了値;
#BETWEENキーワードの前にNOTをつけると指定した範囲以外の問い合わせを行うことができます。
```

###3. IN述語
IN述語は列(column)のデータが指定したいずれかの値と一致した場合にTRUEを返します。TRUEが返された行(row)は問い合わせの対象となります。
WHERE句の後に比較対象としたいcolumn名、その後ろにINキーワードを指定し、カッコ内に一つ以上の値を指定します。

```ruby
SELECT * FROM [table名] WHERE [column名] IN (値１, 値２, ...);
#値が文字列の場合は''をつけ忘れないように注意
```

###4. LIKE述語
LIKE述語は列(column)のデータが指定したパターンと一致した場合にTRUEを返します。TRUEが返された行(row)は問い合わせの対象となります。
WHERE句の後に比較対象としたいcolumn名、その後ろにLIKEキーワードを指定し、最後にパターンを指定します。

```ruby
SELECT * FROM [table名] WHERE [column名] LIKE 'パターン';
```

LIKE述語を使ったパターンの条件指定には以下の特殊記号を使います。

* `%`→0文字以上の任意の文字列
* `_`→任意の一文字

以下のようなfruitsテーブルの例を使って確認しましょう。

| fruits_name |
|:-:|
| みかん  |
| りんご  |
| ぶどう  |
|  バナナ |

####'%'を使ったパターン
この中で「ん」という文字列がデータのいずれかに含まれているパターンは`'%ん%'`となります。
先頭が％であるのは、０文字以上の任意の文字列で開始することを意味し、開始の文字列には制限がないことになります。
文字列の最後も％がつくので、0文字以上の任意の文字列で終了することを意味し、終了の文字列には制限がないことになります。
つまり、「ん」という文字列が含めれているパターンとなり、「みかん」と「りんご」が問い合わせの結果となります。

みかんだけを取り出したい場合は`'%ん'`となります。
これは０文字以上の任意の文字列で開始することを意味し、開始の文字列には制限がないことになりますが、最後が'ん'で終わっているため、最後に'ん'がつく「みかん」だけが対象となります。

####'_'を使ったパターン

パターン`'_ん_'`は、1文字目に任意の一文字、2文字目に「ん」、3文字目に任意の一文字を意味します。
つまり3文字で構成され、2文字目に「ん」がつくデータが問い合わせ対象となり、「りんご」が問い合わせ結果となります。

###5. NULL述語
NULL述語は列(column)のデータがNULL(データが存在しないことを意味する値)の場合にTRUEを返します。TRUEが返された行(row)は問い合わせの対象となります。
WHERE句の後に比較対象としたいcolumn名、その後ろにIS NULLを指定します。

```ruby
SELECT * FROM [table名] WHERE [column名] IS NULL;
#ISとNULLの間にNOTキーワードをつけると列(column)のデータがNULLではない場合にTRUEを返します。
```

##複合条件
複合条件は複数の条件で問い合わせを行います。複数の条件を組み合わせるには、論理演算子を使います。

| 論理演算子 | 条件 |
|:-:|:-:|
| AND  | 複数の条件が全てTRUEの場合に問い合わせの対象となります。  |
| OR  |  複数の条件のいずれかがTRUEの場合に問い合わせの対象となります。 |
| NOT  | 条件がFALSEの場合TRUEを返し、問い合わせの対象となります。  |

```ruby
SELECT * FROM [table名] WHERE 条件１ AND(OR) 条件２;
```

```ruby
SELECT * FROM [table名] WHERE [column名] NOT 条件1;
```

論理演算子には優先順位があり、`NOT`→`AND`→`OR`の順番に評価されます。
また、四則演算と同じように`()`をつけることで優先順位を高めることができます。

##算術演算子
SELECT句で指定した列(column)に計算処理を行うことができます。
計算結果の列(column)についてはAS句を使うことでcolumn名を作成することができます。

```ruby
SELECT [column名]*[column名]等 AS [計算結果のcolumn名] FROM [table名];
```

##集合関数
集合関数を使うと、指定した列(column)の複数のデータを集計することができます。
集合関数には以下のようなものがあります。

| 比較演算子 | 条件 |
|:-:|:-:|
| SUM(列名)  |  指定した列(column)のデータの合計を問い合わせる |
|  AVG(列名) | 指定した列(column)のデータの平均を問い合わせる  |
| MAX(列名)  | 指定した列(column)の最大のデータを問い合わせる  |
| MIN(列名)  |  指定した列(column)の最小のデータを問い合わせる |
| COUNT(列名)  | 指定した列(column)のデータ件数（NULLは除く）  |
| COUNT(＊)  | 表全体のデータ件数（NULLを含める）  |

```ruby
SELECT [集合関数(column名)] AS [集計結果のcolumn名] FROM [table名];
```

##グループ化
グループ化とは、任意の列(column)が同じ値のデータを一つのグループとすることです。
集合関数と組み合わせて使うことで、グループごとの集計を行うことができます。
グループ化を行うには`GROUP BY句`を使用します。

```ruby
SELECT [グループ化対象としたcolumn], [集合関数(column名)] AS [集計結果のcolumn名] FROM [table名] WHERE [条件] GROUP BY [column名];
```

##グループの選択
グループの選択とは、グループ化した集合関数の結果をもとに、条件を満たすグループのみに問い合わせを行うことです。
グループの選択を行うには`HAVING句`を使用します。HAVING句には集合関数の問い合わせ結果を検索条件に指定します。

```ruby
SELECT [集合関数(column名)] AS [集計結果のcolumn名] FROM [table名]  GROUP BY [column名] HAVING [集合関数(column名) 演算子 値];
```

※SQLが実行される順番は
`FROM`→`WHERE`→`GROUP BY`→`HAVING`→`SELECT`
となるのでHAVING句の`集合関数(column名)`で`集計結果のcolumn名`を指定するとエラーになる可能性があります。

##検索結果の並べ替え
検索結果を指定した列をもとに並べ替えを行うことができます。
検索結果の並び替えを行うには`ORDER BY句`を使用します。
ORDER BY句には並べ替えを行いたい列(column)を指定します。
ORDER BY句はSELECT文の最後に記述します。

```ruby
SELECT [column名] FROM [table名]　ORDER BY [column名] ASC(昇順の場合) ;
#降順の場合はDESCオプションを指定します。
#指定しなかった場合は昇順になります。
```

#第２章　SQLによるデータ検索（＋α）

##表の結合
複数の表(table)を繋ぎ合わせ、一つの表(table)として問い合わせることを結合といいます。
結合を行う際は、一方の表(table)の特定の列(column)の値と、もう一方の表(table)の特定の列(column)の値がある条件を満たした場合に組み合わせを行います。
この条件のことを結合条件といいます。
ほとんどの場合は二つの列(column)の値が一致することが結合条件となります。

##内部結合
内部結合は、結合条件が一致した行(row)のみに問い合わせを行います。
内部結合を行うには、`INNER JOIN句`と`ON句`を使用します。
INNER JOIN句には結合する表(table)を指定し、ON句には結合する条件を指定します。

```ruby
SELECT [column名]
FROM [table名1] INNER JOIN [table名2]
ON [table名1.結合キー] = [table名2.結合キー]
#INNER JOIN句のINNERは省略可
```

##左外部結合
左外部結合は結合する２つの表を「左側の表」「右側の表」と定義し、左側の表は全ての行(row)が問い合わせ対象となります。
左外部結合を行うには、`LEFT OUTER JOIN句`と`ON句`を使用します。
LEFT OUTER JOIN句には左外部結合する表(table)を指定し、ON句には結合する条件を指定します。

```ruby
SELECT [column名]
FROM [左側table名] LEFT OUTER JOIN [右側table名]
ON [左側table名.結合キー] = [右側table名.結合キー]
#LEFT OUTER JOIN句のOUTERは省略可
```

##右外部結合
右外部結合は結合する２つの表を「左側の表」「右側の表」と定義し、右側の表は全ての行(row)が問い合わせ対象となります。
右外部結合を行うには、`RIGHT OUTER JOIN句`と`ON句`を使用します。
RIGHT OUTER JOIN句には右外部結合する表(table)を指定し、ON句には結合する条件を指定します。

```ruby
SELECT [column名]
FROM [右側table名] RIGHT OUTER JOIN [左側table名]
ON [右側table名.結合キー] = [左側table名.結合キー]
#RIGHT OUTER JOIN句のOUTERは省略可
```

##完全外部結合
完全外部結合は結合する２つの表を「左側の表」「右側の表」と定義し、左右の表(table)の結合条件の一致、不一致にかかわらず全ての行(row)が問い合わせ対象となります。
完全外部結合を行うには、`FULL OUTER JOIN句`と`ON句`を使用します。
FULL OUTER JOIN句には完全外部結合する表(table)を指定し、ON句には結合する条件を指定します。

```ruby
SELECT [column名]
FROM [左側table名] FULL OUTER JOIN [右側table名]
ON [左側table名.結合キー] = [右側table名.結合キー]
#FULL OUTER JOIN句のOUTERは省略可
```

##副問合せ
副問合わせを使うと、任意のSELECT文の結果を別のSELECT文の検索条件として問い合わせを行うことができます。SELECT文の中の問い合わせのことを副問合わせと
いいます。
メインとなる問い合わせは主問合せといいます。

```ruby
SELECT [column名] 
FROM [table名] 
WHERE [column名 演算子 (副問合せとなるSELECT文)];
```

##限定子
限定子は、副問合せで返された複数の値との比較を行うものです。
限定子は検索条件の演算子として、比較演算子と組み合わせて使用します。

```ruby
SELECT [column名] 
FROM [table名] 
WHERE [column名 比較演算子 限定子 (副問合せとなるSELECT文)];
```

限定子には以下のものがあります。

| 限定子 | 条件 |
|:-:|:-:|
|  ANY(SOME) | 副問合せの結果のいずれかと比較  |
| ALL  | 副問合せの結果の全てと比較  |

ANY(SOME)は、列(column)の値と副問合せの結果を比較し、いずれか一つの値でもTRUEとなった行が問い合せ対象となります。
ALLは、列(column)の値と副問合せの結果を比較し、全ての値とTRUEとなった行が問い合せ対象となります。

##EXISTS
EXISTSは副問合せの結果が、主問合わせで指定した表に存在した行(row)を問い合わせ対象とします。

```ruby
SELECT [column名] 
FROM [table名1] 
WHERE EXISTS 
(SELECT * FROM [table名2] WHERE [table名2.column名] = [table名1.column名]);
```

##UNION
複数の表を用いた問い合わせを行う方法に集合演算子があります。
UNIONは集合演算子の一つです。
結合の場合、複数の表(table)から列(column)と列(column)を繋ぎ合わせ、複数の表(table)を結合した結果を問い合わせます。
集合演算子は複数のSELECT文の結果を一つにまとめて問い合わせを行います。
UNIONでは２つの表(table)に重複する行(row)が存在した場合に一行にまとめます。

集合演算子で問い合わせを行う場合、以下の二つが条件となります。

* 二つのSELECT文の列(column)の数が一致していること
* 二つのSELECT文の列(column)の値のデータ型が同じであること

```ruby
SELECT [column名] FROM [table名]
 UNION
SELECT [column名] FROM [table名];
```

##３つ以上の表の結合
表(table)の結合は３つ以上でも行うことができます。
３つ以上の表(table)で結合を行う場合は、まず２つの表(table)が結合され、この結果に３つ目の表(table)を結合します。
３つ以上の表の結合を行う際にも、`INNER JOIN句`と`ON句`を使用します。
INNER JOIN句には結合する表(table)を指定し、ON句には結合する条件を指定します。

```ruby
SELECT [column名]
FROM [table名1] 
INNER JOIN [table名2]
ON [table名1.結合キー] = [table名2.結合キー]
INNER JOIN [table名3]
ON [table名1.結合キー] = [table名3.結合キー]
#INNER JOIN句のINNERは省略可
```

#第３章　データの変更とトランザクション

##データの挿入
既存の表(table)に新たにデータを挿入する際にはINSERT文を使用します。
INSERT文はINTO句とVALUES句で構成されます。
INTO句で挿入する表(table)と列(column)を指定し、VALUES句で挿入する値を指定します。

```ruby
INSERT INTO [table名(column名1, column名2, ...)] VALUES [(値1, 値2, ...)]
#値が文字列の場合は''をつけ忘れないように注意
```
既存の表(table)に存在している列(column)をINTO句で指定しなかった場合、その列(column)の値はNULLになります。

また、副問合わせの問い合わせ結果を別のテーブルに挿入することもできます。
その場合はVALUES句の代わりに副問合わせを使用します。

```ruby
INSERT INTO [table名1] SELECT * FROM [table名2] WHERE [条件]
```

##データの更新
登録されているデータを更新する際にはUPDATE文を使用します。
UPDATE文はUPDATE句とSET句で構成されます。
UPDATE句で更新する表(table)を指定し、VALUES句で更新するcolumn名と値を指定します。
WHERE句では変更したい行(row)の条件を指定します。

```ruby
UPDATE [table名] SET [column名1 = 値, column名2 = 値, ... ] WHERE [条件]
#値が文字列の場合は''をつけ忘れないように注意
```

##データの削除
登録されているデータを削除する際にはDELETE文を使用します。
DELETE文はFROM句で削除対象の表(table)を指定し、WHERE句で削除したい行(row)の条件を指定します。

```ruby
DELETE FROM [table名] WHERE [条件]
```

##トランザクション管理
トランザクションとは、データベースに対する一連の業務処理基本単位を指します。
トランザクションは一つ以上のSQL文で構成されており、全ての処理が問題なく実行された場合のみ、COMMIT文を実行しデータベースへの変更を確定します。
処理の途中で問題が発生した場合は、ROLLBACK文を実行しデータベースへの全ての変更を取り消します。
トランザクションを開始した場合は、COMMIT文またはROLLBACK文でトランザクションを完了させる必要があります。
これにより、データの整合性を保つことができます。

#第４章　データベースの定義

##表(table)の作成
データベースに新規の表(table)を作成する場合は`CREATE TABLE文`を使用します。

```ruby
CREATE TABLE [table名] (
  [column名] [データ型(長さ)],
  [column名] [データ型(長さ)],
  [column名] [データ型(長さ)],
  [column名] [データ型(長さ)]
);
```

長さとは、対象の列(column)の挿入できる値の最大の桁数を意味しています。

##表(table)の削除
既存の表(table)を削除するためには`DROP TABLE文`を使用します。

```ruby
DROP TABLE [table名]
```

##整合性制約
表(table)を作成する際には制約を定義することができます。
表(table)に制約を持たせることで、制約に違反しているデータを制限することができます。
この制約のことを整合性制約といいます。

###1. NOT NULL制約
NOT NULL制約は特定の列(column)に必ず値を設定するように制限する制約です。
NOT NULL制約は列(column)を定義する際に記述します。

```ruby
CREATE TABLE [table名] (
  [column名] [データ型(長さ)] NOT NULL,
  [column名] [データ型(長さ)]
);
```

###2. 一意性制約
一意性制約は特定の列(column)に重複するデータの挿入や更新をさせないように制限する制約です。
一意性制約には`UNIQUE制約`と`PRIMARY KEY制約`の２種類があります。
UNIQUE制約は、重複するデータを制限はしますが、NULLとすることは可能です。
一方で、PRIMARY KEY制約は重複の制限に加えて、NULLとすることも制限されています。
UNIQUE制約とPRIMARY KEY制約には以下の２通りの記述方法があります。

```ruby
CREATE TABLE [table名] (
  [column名] [データ型(長さ)] UNIQUE,
  [column名] [データ型(長さ)]
);
```

```ruby
CREATE TABLE [table名] (
  [column名] [データ型(長さ)],
  [column名] [データ型(長さ)],
  UNIQUE ([column名])
);
```