SQLを使いこなすために

SQLを書いてみよう

SQLを使いこなせるようになるために、実際に書いてみましょう。
Write your awesome label here.

1. SQLを書いてみよう

ここではDr.Sumの関数を使用して、解説文を見ながら、実際にSQLを書いていただきます。関数は単一ではなく複合して使うことが多いので、ぜひ前章の関数を思い出しながら、挑戦してみてください。

問1:データ型変換とNULL変換

Dr.SumのSQLを使って、文字列を数値に変換し、NULLの場合はNVL関数を使って0に変換する方法を説明します。
具体例 

以下の「売上」テーブルがあるとします。
売上ID
1
2
3
4
5
売上金額(文字型)
3732
44567
NULL
46891
22243
このテーブルで、売上金額(文字型)列を文字列から数値に変換し、NULLの場合は0に変換するSQLクエリを作成します。

SQLの例

以下のSQLクエリを使用します。SQL Executorを開き、データベースを[SQL_Training]に設定して、下記のSQLを入力してみましょう。(コピー&ペーストでもOKです)

各部分の説明

1.  TO_NUMERIC関数:
TO_NUMERICは、文字列の売上金額を数値に変換します。
2.  NVL関数:
NVL(売上金額(文字型), ‘0')は、売上金額(文字型)がNULLの場合は’0'を返し、それ以外の場合は売上金額を数値に変換します。

SQLの中で文字列を入力する場合、'aaa'のようにシングルクォーテーションで文字列を囲む必要があります。
'0'を0とするとエラーになる、これは売上金額(文字型)はこの段階ではまだ文字型なので、「文字としての0」を返してあげる必要があるためです。

結果の例

このクエリを実行すると、以下の結果になります。売上金額は数値型として扱われるため、これらの金額の集計や平均を取得することが可能になります。
売上ID
1
2
3
4
5
売上金額
3732
44567
0
46891
22243

まとめ

  • NVL関数:NULL値を指定したデフォルト値に変換します(ここでは0)。
  • TO_NUMERIC関数:文字列を数値に変換します。

問2:データ型変換と日付計算

売上日から年度を計算する例を示します。
テーブル例 

以下の「売上」テーブルがあるとします。
売上ID
1
2
3
4
売上日
20230415
20230310
20240105
20240220

SQLの例

以下のSQLクエリを使用します。先ほどと同様にSQL Executorで実行してみましょう。

結果の例

売上ID
1
2
3
4
売上日
20230415
20230310
20240105
20240220
年度開始年
2023
2022
2023
2023

説明

  • TO_DATE(売上日, 'YYYYMMDD'):売上日を日付型に変換します。
  • ADD_MONTHS(..., -3):売上日から3ヶ月引いた日付を計算します。
  • TO_CHAR(..., 'YYYY'):3ヶ月引いた日付の年を文字列として取得します。


元々の売上日は文字型で登録されています。-3ヶ月の計算をするためには、文字型を日付型に変換する必要があります。
さらに計算した結果から"年"の部分のみを抽出したいので、文字型でYYYYの部分だけを再度抽出するようにしています。

問3:縦持ちデータを横持ちに変換する

縦持ちデータを横持ちに変換するためのSQLについて説明します。これを「ピボット」と呼びます。ピボット操作は、データを行から列に変換するために使用されます。
縦持ちデータの例 

以下の「売上」テーブルがあるとします。
売上ID
1
1
1
2
2
3
3
3
4
1月
2月
3月
1月
2月
1月
2月
3月
1月
売上金額
124
4345
6733
235
346
5674
4326
564
243
このデータは月のデータがレコードごとに入っていますが、1月,2月・・・が列(カラム)になるように変換します。

SQLの例

今までに学習した知識を応用すると条件付き集計関数(CASE文とSUM関数)を使用して同様の結果を得ることができます。以下はその一例です。

結果

売上ID
1
2
3
4
1月
124
235
5674
243
2月
4325
346
4326
0
3月
6733
0
564
0
このクエリは、各売上IDごとに月ごとの売上金額を列に展開します。

解説

1.  CASE文
  • CASE WHEN 月 = '1月' THEN 売上金額 ELSE 0 END:月が1月の場合、売上金額を返し、それ以外の場合は0を返します。
  • 同様に2月と3月の条件も設定します。
2.  SUM関数
  • SUM関数を使用して、各売上IDごとの月別売上金額を集計します。
3.  GROUP BY句
  • 売上IDでグループ化することで、売上IDごとにデータを集計します。

ASのあとに列名を名付けているけど、[1月]のように全角数字を使用しているね。これは列名の先頭文字に半角英数や半角記号を入れると、エラーになってしまうから全角文字を使っているんだよ!

PIVOT関数をつかおう

さきほどはCASE式を使用して、横持ちデータに変換をしていましたが、Dr.SumはPIVOT関数があります。
PIVOT関数を使う方法を説明します。

PIVOT関数を使ったSQLクエリ

Dr.SumのPIVOT関数を使って、このデータを横持ちに変換するSQLクエリは次のようになります。

各部分の説明

1.  PIVOT句
  • PIVOT (SUM(売上金額) FOR 月 IN ('1月' AS 1月, '2月' AS 2月, '3月' AS 3月)) 売上金額:ここで、SUM(売上金額)は売上金額を合計する集計関数です。FOR 月 INはピボットに使用する列を指定します。

結果の例

このクエリを実行すると、以下のような結果が得られます。
売上ID
1
2
3
4
1月
124
235
5674
243
2月
4325
346
4326
0
3月
6733
0
564
0
この結果では、各月の売上金額が別々の列として表示されています。

さっきのCASEよりもPIVOTの方が文字が少なくてすっきりしているね。
すっきりしているだけでなく命令が少ないのでPIVOTの方がCASEを多用するよりも
データが返ってくる時間が早いんだよ! 慣れてきたらSQLの効率も考えていこうね。

まとめ

  • PIVOT関数を使うことで、縦持ちデータを横持ちデータに変換できます。
  • PIVOT関数の基本構文は、PIVOT (集計関数 FOR ピボットに使う列 IN (列名1, 列名2, ...))です。

2. これができたらあなたは初心者の壁えている

さて、ここまででたくさんのSQLを書いていただきました。SQLには慣れてきたでしょうか?
いままでに学習したことを応用すればあなたは"SQLの書ける人"と周りから思われるようになるでしょう。

しかし今回のコンテンツは"はじめてのSQL"なので、実はまだまだSQLは奥深いです。
本コンテンツの最後として、少しだけ初心者の壁を超えたSQLの紹介をします。
  • サブクエリーを使ってみる
  • 階層構造を作ってみる

ここは「SQLをもっと極めるとこんなこともできるんだ」と認識してもらうための
コンテンツだよ。実際にSQLを書かなくてもOKなので、気楽に読み進めていこうね!

サブクエリー

サブクエリー(サブクエリ)は、SQLの中で別のSQLを使用する方法です。サブクエリーを使うと、複雑なデータの抽出や分析が可能になります。
Dr.Sumでもサブクエリーを使ってデータを操作することができますので、どのように記述をするのか確認をしてみましょう。

例を使った説明

例 1

最も売上が高いレコードを持つ従業員を取得する

SQLの例:

結果:

従業員ID
10
売上金額
49986

説明:
[
売上データ]テーブルにはさまざまな従業員の売上データがたくさん入っています。従業員ひとりひとりにもたくさんのレコード情報があります。その中で最大の売上金額を持つ従業員を抽出してみました。

例 2

各部署ごとの売上総額と、各部署に所属する従業員ごとの売上総額を計算し、それぞれを表示する

各部署の売上金額の合計と各従業員の売上金額の合計はGROUP BYの集計単位が異なるため、複数回クエリをまわさねばならないですが、サブクエリーをつかうとひとつのSQLの中で完結することができます。

SQLの例:

結果:

部署名
営業1部
営業1部
営業2部
営業3部
部署売上
9166028
9166028
14107054
2500306
従業員名
中村
吉見 
一ノ瀬
佐久間
従業員売上
1228199
1419324
1391639
1278537

詳細な説明

部署ごとの売上総額を計算するサブクエリー (部署クエリ)

1.  テーブル結合:
売上データテーブル、従業員マスタテーブル、および部署マスタテーブルをJOINします。売上データテーブルの従業員IDを従業員マスタテーブルの従業員IDと結合し、次に従業員マスタテーブルの部署IDを部署マスタテーブルの部署IDと結合します。
2.  集計:
各部署名ごとに売上金額の合計を計算し、部署売上として表示します。

従業員ごとの売上総額を計算するサブクエリー (従業員クエリ)

1.  テーブル結合:
売上データテーブル、従業員マスタテーブル、および部署マスタテーブルをJOINします。売上データテーブルの従業員IDを従業員マスタテーブルの従業員IDと結合し、次に従業員マスタテーブルの部署IDを部署マスタテーブルの部署IDと結合します。
2.  集計:
従業員名ごとに売上金額の合計を計算し、従業員売上として表示します。

メインクエリー

1.  サブクエリーの結合:
部署ごとの売上総額を計算した部署クエリと従業員ごの売上総額を計算した従業員クエリ部署名で結合します。
2.  選択:
部署名、部署ごとの売上総額(部署売上)、従業員名、従業員ごとの売上総額(従業員売上)を選択します。
いかがでしたでしょうか? 長文のSQLとなり、「見たくない」と最初は思ったでしょうが、よくよく紐解いてみると、今までの復習の情報でこのSQLが書けてしまいます。ぜひ少しだけ勇気を出して長いSQLも読み解いていけるようにしましょう!

階層構造をつくる


BIツールでおなじみのドリルダウン。
大分類ごとの売上 → 大分類・中分類ごとの売上 → 大分類・中分類・小分類ごとの売上 のようにどんどんと細かい情報にしてデータ分析をする方法です。
この機能を使いたいのにデータが階層ごとになっていないからうまくできない、ということはございませんか?
ここではカラム内の文字列の中で特定の文字列で分割して、階層項目をつくるという内容です。

SQLを使うパターン

簡単な説明

ここでは'https://navi.wingarc.com/product/drsum/12506'のように、'/'(スラッシュ)が含まれている文字列ごとに階層分けして列に格納するSQLを記載しています。上記のようにCASE文を多用してSQLで作ることも可能です。

ぜひ下記の記事を参考にしてください。

特定の文字列で分割して階層構造をつくりたい!~SQLで分割する~ | WingArc TECH BLOG

しかしDr.SumにはDS Scriptというひとつのプログラムの中でより複雑なSQLを記述できるスクリプトが存在します。そちらの例を参考にしてみましょう。

DS Scriptを使うパターン

ここでは先ほどのSQL文よりも高度なことをしています。先ほどは'/'(スラッシュ)の数を決め打ちしていました。そのため11個目の'/'(スラッシュ)が文字列の中にある場合は対応できていません。
こちらのDS Scriptではループ処理があるので、’/’(スラッシュ)の数の最大数を指定しておいて、その数だけループ処理を回しています。

ぜひ下記の記事を参考にしてください

特定の文字列で分割して階層構造をつくりたい!~DS Scriptで分割する~2

3. さいごに

最後までコンテンツを進めてくださりありがとうございます。SQLについて最初の一歩が踏み出せましたでしょうか? ぜひフィードバックやコメントをお寄せいただけると幸いです。

SQLは難しいと感じられがちですが、ひとつずつ紐解いていくと、「あ、こうなのか」と理解ができると思います。
難しいSQLに直面しても、わかるところを見つけ、ひとつずつ解決をしていくようにしましょう。
ここまでSQLを学習したあなたなら、以前より高度なデータ分析ができるように
なってるよ。自信を持って日々の業務に取り組もう!

他のコンテンツもぜひチェックしてみてね!!

さいごに、ぜひフィードバックをお聞かせください