はじめに
実務未経験でWebエンジニアとして入社してからの2カ月で受けた社内研修についての振り返りです。
SQL のデータ取得( SELECT 文)の答案へのレビューをいくつかピックアップして、SQL文のビフォーアフターを比較します。
記事の目的
同時期に実務未経験でWebエンジニアになって交流している方々(他社の)が、
「他の人が初期にどのような注意を受けているか聞いてみたい」
と言っていたため、私は自分が書いたコードをレビューしてもらった機会はまだ研修のみですが、どのような点をレビューで教えてもらったかについて、共有したいと思います。
振り返りを通して、私自身現在忘れてしまわずに身になっているか確認していきます。
想定する読者
想定する読者は、実務未経験の初学者の方です。(過去の自分を想定して書いてます)
どんな社内研修?
社内研修は、Web開発全般についての基礎的な研修で、以下のカリキュラムでした。
- PHPの基礎(PHP、オブジェクト指向)
- データベースの基礎(SQL、MySQL)
- Webアプリケーション基礎(HTML、CSS、CRUD、Cookie、セッション)
これらの内容についての課題を解いていき、 GitLab でマージリクエストして、 社内のエンジニア の方にレビューをいただく、という流れです。
※ 社内研修コードレビュー記事
SQLの課題は例えば下記のようなものでした。
商品テーブルの内容を全て出力するSQLを作ってください
このようにSQLの基礎文法の理解を問う問題が20問ほどあり、OKもらえるまで修正します。
※ データ取得、データ操作、テーブル操作、トランザクションなどの問題がありました。
目次
今回は「データベースの基礎」の課題について、 SQL のデータ取得( SELECT 文 )のレビュー内容に絞って、整理していきたいと思います(一番レビューで色々と指摘があったため)。
以下の8つのレビューをピックアップしました。
※ 「答案ビフォー」→「レビュー」→「答案アフター」→「メモ」という構成です。
※ ビフォーとアフターとで、取得しているデータは一緒です。
1. 「SQLコーディングスタイルを決めましょう」
レビュー
SQLのコーディングルールがなくて困りますね。これで統一しましょう。
実務では現場のコーディングスタイルをまずは確認してください。
メモ
- レビューというか、レビューをする前の意識合わせです。インターネットで検索した限りでは SQL のコーディングスタイルは、どの書き方が主流かわからず、人それぞれな印象でしたが、現場ではどうなんでしょう。
2. 「複数取得できる場合は、かならず ORDER BY
を記載する癖をつけてください」
ビフォー
SELECT
product_id,
product_name,
color,
price,
delete_flag,
created_at,
updated_at
FROM
products
;
レビュー
複数取得できる場合は、かならず ORDER BY
を記載してください。そうする癖をつけておくようにしてください。
アフター
SELECT
product_id,
product_name,
color,
price,
delete_flag,
created_at,
updated_at
FROM
products
ORDER BY
product_id ASC
;
メモ
- 「なぜ、かならず
ORDER BY
を記載すべきか」の理由について自分でも考えてみると、「並び順を何も指定しないと、取得される表示順についてどのように表示されるか保証がない。実務では指定するため、指定する癖をつけよう」ということだと認識しています。
3. 「IN
を使って、条件を1行で書いてください」
ビフォー
SELECT
product_id,
product_name,
color,
price,
delete_flag,
created_at,
updated_at
FROM
products
WHERE
color = '赤'
OR
color = '青'
ORDER BY
product_id ASC
;
レビュー
IN
を使って、条件を1行で書いてください。
アフター
SELECT
product_id,
product_name,
color,
price,
delete_flag,
created_at,
updated_at
FROM
products
WHERE
color
IN
(
'赤',
'青'
)
ORDER BY
product_id ASC
;
(コーディングスタイルの関係で1行では書けていませんが…)
メモ
- 「なぜ、
IN
を使う方がいいか」の理由について考えると、「さらに’黒’,'白’
…と要素が増えていっても、簡潔に書けるよ」ということだと考えています。
4. 「 カウント関数の中に、条件書かずに、WHERE
句に条件を記載してください」
ビフォー
SELECT
COUNT(
gender = '男'
OR
NULL
) AS '男性の人数'
FROM
members
WHERE
delete_flag = 0
;
レビュー
カウント関数の中に、条件書かずに、WHERE
句に条件を記載してください。単純なcountを使うSQLは、count(*)
が一般的です。
アフター
SELECT
COUNT(*) AS '男性の人数'
FROM
members
WHERE
delete_flag = 0
AND
gender = '男'
;
※ OR NULL
は変更後の書き方では不要になったため削除しました。
メモ
- 「なぜ、カウント関数の中に、条件書かずに、
WHERE
句に条件を記載するのか」の理由について軽く考えましたが、今のところよくわかっていません。SQL文の書きやすさ、読みやすさはありそうですね。ひとまず「一般的」な書き方で書いていきます。
5. 「テーブル結合は基本的に JOIN ON
を用いてください」
ビフォー
SELECT
SUM(sales.quantity * products.price)
FROM
sales, products
WHERE
sales.product_id = products.product_id
;
レビュー
SQL/コーディングスタイル にて、
JOIN ON句
結合は基本的に
JOIN ON
を用いてFROM
に複数 +WHERE
句で結合条件という記述をしない
と記載のとおり、修正してください。
アフター
SELECT
SUM(sales.quantity * products.price)
FROM
sales
INNER JOIN
products
ON
sales.product_id = products.product_id
;
メモ
- 「なぜ、
FROM
に複数 +WHERE
句で結合条件という記述をしないで、結合は基本的にJOIN ON
を用いるのか」の理由について調べてみると、「ビフォーのようなFROM
に複数 +WHERE
句で書く方法は 単純結合 と呼ばれて、sales
テーブルとproducts
テーブルのすべての組み合わせのレコードが返されて、データ数が多くなってしまうため」ということになると考えます。
6. 「AS
で別名つけてください」
ビフォー
SELECT
SUM(sales.quantity * products.price)
FROM
sales
INNER JOIN
products
ON
sales.product_id = products.product_id
;
レビュー
AS
で別名つけてください。
アフター
SELECT
SUM(s.quantity * p.price) AS '売り上げの合計'
FROM
sales AS s
INNER JOIN
products AS p
ON
s.product_id = p.product_id
;
メモ
- 「なぜ、
AS
で別名つけるのか」の理由については、「カラムやテーブルに別名を付けることで読みやすくなったり、簡潔になるため」だと考えています。
7. 「 結合に関連しない条件は、JOIN
したあとに記載してください」
ビフォー
SELECT
SUM(s.quantity * p.price) AS '非会員の売り上げの合計'
FROM
sales AS s
INNER JOIN
products AS p
ON
s.product_id = p.product_id
AND
s.member_id IS NULL
;
レビュー
INNER JOIN
の ON
句に、salesの条件があると読みにくいので、 sales の条件(s.member_id IS NULL
)は JOIN
したあとに記載してください。
アフター
SELECT
SUM(s.quantity * p.price) AS '非会員の売り上げの合計'
FROM
sales AS s
INNER JOIN
products AS p
ON
s.product_id = p.product_id
WHERE
s.member_id IS NULL
;
メモ
- 理由については、sales テーブルと products テーブルの結合条件として、「salesの条件があると読みにくい」ということでした。
- 実行コストは変わらないのかなどはわかっていません。
8. 「GROUP BY
を使った SQL に変えてください」
ビフォー
SELECT
SUM(
CASE WHEN m.gender = '男'
THEN s.quantity * p.price
ELSE 0 END
) AS '男性会員の売り上げの合計'
,
SUM(
CASE WHEN m.gender = '女'
THEN s.quantity * p.price
ELSE 0 END
) AS '女性会員の売り上げの合計'
FROM
sales AS s
INNER JOIN
products AS p
ON
s.product_id = p.product_id
INNER JOIN
members AS m
ON
s.member_id = m.member_id
;
レビュー
GROUP BY
を使ったSQLに変えてください。
アフター
SELECT
m.gender,
SUM(s.quantity * p.price) AS '売り上げの合計'
FROM
sales AS s
INNER JOIN
products AS p
ON
s.product_id = p.product_id
INNER JOIN
members AS m
ON
s.member_id = m.member_id
GROUP BY
m.gender
;
メモ
- 理由について考えると、CASE式より明らかにスッキリしましたし、種類ごとに集計したいときは
GROUP BY
で良いと考えています。 - 取得した結果は同じでも、SQL文の可読性や、実行コストも考慮できるようになっていきたいです。
おわりに
未だ実務で SQL には触れていないこともあり、研修当時からあんまり理解度は変わってない気がする、という危機感があったので、それだけでも今回Qiita記事にまとめ直して、振り返った甲斐がありました…
あと、レビューでそのように書いた方が良いと言っていただく際に理由は添えられていなかったので、理由も理解する必要があると思い、記事にまとめ直す際にメモを書き足してみました。
この記事に対してのレビューもお待ちしております!
ありがとうございました!