【SQL】可読性を上げるために意識していること

# はじめに

「SQLといえば、エンジニアが扱うスキル」と思われがちですが、最近はマーケターや営業など、非エンジニアの方もSQLを使って自らデータを抽出し分析する方が増えてきています。
また豊富な参考書や学習サイトもあり、SQL自体の学習はとてもしやすい環境にあります。
しかし、SQLの**可読性**という点について解説されている学習ツールはあまり見かけないのも事実です。

より正確に(意図しないデータを含めずに)データを抽出するため、また他者に対してロジックの解読をしやすくするためにも、**可読性**を意識することはSQLにおいてとても重要なスキルと言えるでしょう。

今回は、ここ数年ほぼ毎日のようにSQLを書いてきた経験をもとに、**可読性**を上げるために意識していることを書きだしてみました。

**※記述ルールに正解はないため、もし違う流派の方がいれば、ぜひコメントで紹介していただけると嬉しいです:blush:**

# 1. 予約語は大文字で書く

それ自体に特別な意味をもつ語句のことを**予約語**と呼びます。
SELECTやFROMといった句はもちろんのこと、CASE式や、COUNT()、OVER()といった関数なども予約語に含まれます。
ただし、RDBMSやそのバージョンによっても予約語の範囲が違うため、**テーブル名とカラム名以外は大文字で書く**という意識を持つようにしています。

![無題のプレゼンテーション (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311026/1ebac4cb-3074-1b4a-0abe-505fcfcff5a7.png)


# 2. CASE式は予約語ごとに改行する

CASE式で使われる主な予約語は、CASE、WHEN、THEN、ELSE、ENDの5つです。
**これら予約語ごとに改行する**ことで、条件の追加や削除がしやすくなる他、検索CASE式場合は条件部分の可読性の向上にも繋がります。


![無題のプレゼンテーション (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311026/fcf1f134-1e30-7dbb-9de1-95824e1ede59.png)


# 3. AND,ORは先頭に書き、基本的に1行1条件で書く

WHERE句、ON句、CASE式といった条件を記述する際に使われるのがAND、ORです。
SQLにおいて、ANDとORの数が多ければ多いほど複雑なSQLになっていく傾向があります。
SQLは複雑になればなるほど、意図しないデータを抽出してしまう危険性が高くなり、その先で待っている意思決定にも影響を及ぼしてしまいます。

しかし、前処理をするために多用せざるを得ない場面もあるのも事実です。
全体の行数は増えてしまいますが、少しでも可読性を上げ、意図しないデータを抽出してしまう危険性を下げるためにも、私は**1行に対して1条件**を意識して書くようにしています。

![無題のプレゼンテーション (4).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311026/bec27b2f-d497-eeae-c990-1458ce2412f8.png)



# 4. SELECT句で複数列出力する場合は、先頭に,(カンマ)を書く

可読性の高さは、エラーの発見のしやすさに比例します。
初心者がよくやりがちなエラーとして、SELECT句の最後が,(カンマ)で終わっているパターンがあります。
これは、複数列出力する際に文末に,(カンマ)を書いていて、途中で一番最後の列を削除した際に、その1つ前の列のカンマを消し忘れたときに起きるエラーです。
単純なエラーが故に原因に気づくことが難しく、「このSQLのエラーが解消できません…」と相談をもらうことが多々ありました。
先頭に,(カンマ)を書くことでその1行のみを消すだけで済むため、複数列出力する場合は、**先頭に,(カンマ)を書くこと**を推奨しています。

![無題のプレゼンテーション (5).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311026/4a5c7b8e-e80a-783b-cf82-94b797863e50.png)


# 5. JOINの有無に関わらず、テーブル名.カラム名でカラムを記述する

テーブル名.カラム名と記述することで、どのテーブルのカラムなのかを宣言することができます。
主に複数テーブルで同一名のカラムがある際に使われますが、**FROM句のみ(JOIN句を使わない)場合でもテーブル名.カラム名と記述する**ようにしています。

理由としては、記述途中で別テーブルをJOINしないといけなくなった際に、今まで書いてきたものを見直して1つ1つどのテーブルのカラムなのかを確認しなくて済むためです。
また同一名ではないにしてもテーブル名を付けておくことで、そのカラムがどういったデータを表すカラムなのかを推測するできるメリットもあります。

ちなみに、ASを使うことでテーブルに別名を宣言することができるのですが、私は**敢えて使わずにテーブル名をそのまま使っています**。
例えば、membersテーブルをm、ordersテーブルをoと別名宣言した場合。
他者がそのSQLを読む際に、最初に「このテーブルはこの別名がついている」という理解を求めることになり、それが可読性の低下に繋がるため、敢えてASによる別名宣言を使わないようにしています。

![無題のプレゼンテーション (6).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311026/dba09af0-76d7-a300-0681-46ffc77221b7.png)


# 6. 1行で完結する場合はサブクエリ、そうでなければWITH句を使う

SQLの可読性を低下させる最たる要因がサブクエリ(副問合せ)の存在でしょう。
これが何重にも使われると、誰も読みたがらないダークマターが出来上がります…。
しかし、EXISTS関数を利用したり、前処理を行う上で必要な技術でもあります。

サブクエリを使うか、WITH句を使うかの線引ですが、私は**1行で完結できるか**を基準にしています。
具体的には、

``` sql
SELECT カラム名 FROM テーブル名 WHERE 条件1
```

程度であれば、半角スペースで繋げてサブクエリとして記述しています。
よくあるのが、EXISTS関数を使う場合ですね。
それ以外は、今まで書いた記述ルールを踏襲した上で、WITH句で宣言するようにしています。


![無題のプレゼンテーション (7).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311026/6046d9d1-8c3d-8954-6896-b693e6f6af58.png)

  
# 7. インデントは半角スペース2つ

行の先頭に空白を入れて、行の開始位置をずらすことをインデントと呼びます。
インデントを行うことで、各処理を視覚的にグルーピングすることができるため、修正や確認を行う際に該当処理に対する把握のしやすさを向上させることができます。

その際、半角スペース2つ派、半角スペース4つ派など、人によって違いが出ます。
インデントが複数回発生した場合に、**半角スペース4つ以上だと1行あたりの横幅が長くなってしまい可読性の低下に繋がるため**、私は半角スペース2つでのインデントをしています。


# おわりに

普段知らず知らずのうちに同じ書き方をしている人もいれば、全く違う書き方をしている方もいるでしょう。冒頭でも書きましたが、**記述ルールに正解はありません**。所属している組織や普段のタイピングの仕方によっても、可読性の「良い」「悪い」は変わってくるでしょう。

ですが、もしあなたが特にこだわりを持っていなかったり、これからSQLを勉強しようとしている人なのであれば、ぜひ今回紹介した記述ルールに沿って書いてみてください。すぐにはメリットを感じられないかもしれませんが、手に馴染んでくるとSQLの記述や読解の効率が上がってくるはずです！

そして、ぜひ自分なりの可読性を意識した記述ルールを見つけてみてください:blush:

それでは、よきSQLライフを！:thumbsup: