見出し画像

Tableauで学ぶSQL

皆様こんにちは。DATA Saber - Bridge 3rdに挑戦中のNaoです。
私事ですが、最近職場でデータ基盤のチームに異動したこともありSQLを勉強しています。勉強をしていて、私のようにSQLはほぼ未経験だがTableauの経験はそれなりにある人は、Tableauを使いながらSQLを学ぶことで効率的にインプットできるのでは、と思いました。

まだ初学者の身ですが、この内容がどなたかの参考になれば幸いです。


私が考えるTableauを使いながらSQLを学ぶメリット

まず、SQLとはデータベースを操作する言語であり、データの追加、更新、削除などデータベースに関する様々なことができますが、Tableauにも関係するものではデータの抽出ができます。

勿論、ただ全データを抽出するのではなく必要なカラムのみに絞ったり、指定の粒度で集計したり、カラムの中の一部の項目のみに絞って抽出することができます。他にも昇順と降順でのソートや上位N位のリストアップなど、様々な条件での抽出が可能です。

ここで、上記の操作はTableauでも可能でそれぞれ以下のように捉えることができます。

  • 「指定の粒度で集計」→ディメンションとメジャーを配置して集計する

  • 「カラムの中の一部の項目のみに絞る」→ディメンションフィルター

  • 「昇順と降順でのソート」→並び替え、RANK関数

  • 「上位N位のリストアップ」→Top Nフィルター

このように、Tablaeuでクロス集計表を作ることはノーコードでSQLを書くことと同義だと私は思います(そもそもTableauの裏でSQLが動いている)。そのため、一度Tableauで作った集計表をSQLで再現することでSQLの理解につながると考えます。すでに正解はTableauで作っているので答え合わせが楽な点もメリットです。

実践

こちらで紹介されている問題をSQLを使って解いていきます(Tableauのバージョンが異なるため答えも異なることにご注意ください)

使用データはサンプルスーパーストアです。カスタムSQLの使い方はこちらをご覧ください(データベースはBigQuery等他のものでも問題ございません)。また、カラム名のみ英語に変換しております。

1. 利益が赤字のサブカテゴリは?

A. テーブル、本棚、文房具

問1:Tableau上での集計結果

SQL文

select Sub_Category, SUM(Profit) as Profit
from <dataset_name>.<table_name>
group by Sub_Category
having Profit < 0

select : 取り出すカラムの指定
as : 出力時のカラムの別名
from : カラムを持つテーブル
group by : 数値(ここでは利益)を集計する粒度(ディメンション)
having : 集計結果の絞り込み(メジャーフィルター)

サブカテゴリ別の合計利益を見るため、まずはその2つのカラムを抽出します。この時、利益をSUMで囲みます(平均値をとる時はAVG、最小値をとる時はMINなど、この辺りはTableauと同じです)。
そして、group byで集計粒度であるサブカテゴリを指定します。最後のhavingが無くても全サブカテゴリ別の利益が出るだけで問題自体は解けますが、必要な情報のみに絞ります。

問1:SQLでの集計結果

2. 売上が最も高い顧客の利益は?

A. -297,111

問2:Tableau上での集計結果

SQL文

select Customer_Name, SUM(Profit) as Profit, SUM(Sales) as Sales
from <dataset_name>.<table_name>
group by Customer_Name
order by Sales DESC

order by : 集計結果を昇順、降順で並べ替える処置(昇順:asc 降順:desc)

selectで必要なカラムを取り出し、group byで必要な粒度で集計するまでは1. と同じです。今回は最も大きい売上を持つ顧客の利益を聞かれているので、Salesを降順にソートします。

問2:SQLでの集計結果

3. 顧客名ごと合計売上の平均が最も高い顧客区分は?

A. 企業

問3:Tableau上での集計結果

補足:計算1 の中身

{FIXED [顧客区分], [顧客名] : SUM([売上])}

SQL文

select Segment, AVG(Total_Sales_by_Customer) as Avg_Sales_by_Segment
from (
select Segment, Customer_Name, SUM(Sales) as Total_Sales_by_Customer
from <dataset_name>.<table_name>
group by Segment, Customer_Name
) 
group by Segment

サブクエリ:SQL文の中に書く別のSQL文

この問題は最初に顧客別の合計売上を算出したあとに、その値を用いて顧客区分別の平均値を算出します。この場合はSQLを2つに分け、サブクエリで先に集計した値をメインクエリで引用し、最終的な答えを求めます。
fromの括弧内で顧客区分、顧客名別の合計売上を算出します(後で顧客区分別に集計するため、サブクエリの段階からgroup byで顧客区分を指定します)。そして、メインクエリではこの値の平均値を顧客区分別に集計します。

問3:SQLでの集計結果
補足:サブクエリの集計結果

4. 最も件数が多い数量は?

A. 2つ

問4:Tableau上での集計結果

SQL文

select Quantity, COUNT(*) as record_count
from <dataset_name>.<table_name>
group by Quantity
order by record_count desc

サンプルスーパーストアは注文1回ごとにレコードがつき、売上、利益、数量等が記録されます。今回は、数量ごとにレコード数をカウントし、一度に何個纏めて買われることが多いかを見る問題です。
これまでのSUM()やAVG()と同様に、COUNT()で対象のレコード数をカウントできます。ここで、*はテーブル全体を指します。つまり、COUNT(*)でテーブル全体のレコード数をカウントし、これを数量ごとに集計します。

問4:SQLでの集計結果

5. カテゴリごとの都道府県合計売上をみると、一番高いのはすべて大阪府。では一番合計売上が低い都道府県は?

A.  テクノロジー:鹿児島県、家具:熊本県、事務用品:和歌山県

問5:Tableau上での集計結果

補足:計算2の中身

RANK(SUM([売上]), 'asc') = 1

SQL文

with RankedSales as (
select Category, Prefecture, SUM(Sales) as Sales, 
rank() over (partition by Category order by SUM(Sales) asc) as Sales_Rank
from <dataset_name>.<table_name>
group by Category, Prefecture
)
select Category, Prefecture, Sales
from RankedSales
where Sales_Rank = 1

with : 一時的にサブクエリを別名で管理する機能。後のSQL文でこの別名を引用してサブクエリを呼び出せる。
rank : 指定のグループや基準でランクを付ける機能
partition by : ランクを付ける際のグループ。今回はカテゴリごとに計算するためCategoryを指定
order by : 並び替えの基準となる値。今回は合計売上が最も小さい都道府県を求めるため、SUM(Sales) ascを指定
where : 抽出対象の絞り込み(メジャーフィルター)

with句のサブクエリ内でランキングを計算します。カテゴリ、都道府県別に合計売上を集計し、さらにカテゴリ内での売上のランキングを計算します。今回はascを指定しているため、売上が最小の都道府県に1が割り振られます。
この結果をメインクエリで呼び出します。その際に、whereでランクが1(売上が最小)の都道府県のみを取り出すように指定します。

問5:SQLでの集計結果

最後に

今回は、Tableauの集計結果をSQLで再現してみました。ある程度Tableauの経験がある方は、Tablaeuの機能とSQLの構文の対応関係を考えながら再現することでイメージしやすく、SQLへの理解が深まるのではと考えます。


いいなと思ったら応援しよう!