7. SQL演習#
SQLの基本を体に染みこませるために,本演習では細かな課題「ノック」を大量に解く.
架空のショッピングサイトVirtualStoreにおける商品管理,購買履歴管理のために運用されている関係データベースにアクセスできるとの想定の下,様々なデータ要求に応えるためのSQL文を書く練習(ノック)を行う.
本演習では,関係データベースの管理システム(DBMS)の中でも環境構築がカンタンで軽量なDBMSであるSQLiteを用いる.
演習で用いる関係データベース(virtual_store)には,下記テーブルが格納されている:
receipt: レシート明細に関するテーブルstore: 店舗情報に関するテーブルproduct: 商品情報に関するテーブルcategory: 商品カテゴリに関するテーブル
これらテーブルに対してSQL文を実行し,データベースに対する問い合わせの練習を行う. ノックの数は合計25である. どのノックも前章までに解説した内容に即したものになっている. 適宜過去資料を振り返りながら,各ノックに取り組むこと.
なお,演習を始める前に,必ずJupyter NotebookもしくはGoogle Colaboratory上で以下のコードを実行すること.
演習で用いるSQLiteデータ(virtual_store.db)のダウンロード,およびSQLiteの実行環境設定を自動で済ませることができる.
import os
# 演習で用いるデータのダウンロード
if not os.path.isfile('data/virtual_store.db'):
os.makedirs('data', exist_ok=True)
!wget -P data https://github.com/hontolab-courses/database-lecturenote/raw/main/content/exercise/data/virtual_store.db
!pip install jupysql
%load_ext sql
%config SqlMagic.feedback = 0
%sql sqlite:///data/virtual_store.db
7.1. 演習で用いるデータおよび課題の出典について#
本演習課題で用いるデータは,データサイエンティスト協会スキル定義委員の「データサイエンス100本ノック(構造化データ加工編)」で配布されているデータを,わたし山本がSQLite形式に変換したものである. また,演習内容(ノック)はデータサイエンス100本ノック(構造化データ加工編)に収録されている演習課題を,本講義向けにアレンジしたものである.
下記のとおり,元データの著作権やライセンスは,MITライセンスに従う.
Copyright (c) 2020 The Japan DataScientist Society
Released under the MIT license
https://raw.githubusercontent.com/The-Japan-DataScientist-Society/100knocks-preprocess/master/LICENSE
Important
レポート課題1(SQL)
本ページで出題されているすべての課題を解きなさい. 解答期日,解答方法等については下記を参照すること.
設問数:25
成績評価における本課題の割合:20%(20点)
評価方法
Q1-Q5を全問正解した学生のみ,Q6以降を採点対象とします
Q6-Q25のSQLの実行結果をもとに,1問1点で採点します(最大20点)
解答〆切り:2025年6月16日 (日)23:59( 解答は締め切りました )
解答提出方法:解答用サイトSQL Autograder経由
備考:〆切り以降に提出された解答は,本人の責めに帰さない限り,別途受理します.
7.2. SQL Knock 25連発#
7.2.1. Knock 1: 選択#
レシート明細のテーブル(receipt)から先頭10件を表示するSQL文を書け.なお,表示する列はreceiptテーブルがもつ全列(sales_ymd, sales_epoch, …)とする.また,列の表示順はreceiptテーブルで定義された列の順序に従うこと.
%%sql
7.2.2. Knock 2: 射影1#
レシート明細のテーブル(receipt)から先頭10件を表示するSQL文を書け.ただし,表示する列およびその表示順序は売上日(sales_ymd),顧客ID(customer_id),商品コード(product_cd),売上金額(amount)とする.
%%sql
7.2.3. Knock 3: 射影2#
レシート明細のテーブル(receipt)から先頭10件を表示するSQL文を書け.ただし,表示する列およびその表示順序は売上日(sales_ymd),顧客ID(customer_id),商品コード(product_cd),売上金額(amount)とする.また,列sales_ymdは列名をsales_dateに変更すること.
%%sql
7.2.4. Knock 4: 選択2#
レシート明細のテーブル(receipt)から以下の条件を満たすレコードをすべて抽出するSQL文を書け.
顧客IDが”CS018205000001”
ただし,表示する列およびその表示順序は売上日(sales_ymd),顧客ID(customer_id),商品コード(product_cd),売上金額(amount)とする.
%%sql
7.2.5. Knock 5: 選択3#
レシート明細のテーブル(receipt)から以下の条件を満たすレコードをすべて抽出するSQL文を書け.
顧客IDが”CS018205000001”
売上金額が1000以上
ただし,表示する列およびその表示順序は売上日(sales_ymd),顧客ID(customer_id),商品コード(product_cd),売上金額(amount)とする.
%%sql
7.2.6. Knock 6: 選択4#
レシート明細のテーブル(receipt)から以下の条件を満たすレコードをすべて抽出するSQL文を書け.
顧客IDが”CS018205000001”
売上金額が1000以上2000以下
ただし,表示する列およびその表示順序は売上日(sales_ymd),顧客ID(customer_id),商品コード(product_cd),売上金額(amount)とする.
%%sql
7.2.7. Knock 7: 選択5#
レシート明細のテーブル(receipt)から以下の条件を満たすレコードをすべて抽出するSQL文を書け.
顧客IDが”CS018205000001”
売上金額が1000以上または売上数量が5以上
ただし,表示する列およびその表示順序は売上日(sales_ymd),顧客ID(customer_id),商品コード(product_cd),売上数量(quantity),売上金額(amount)とする.
%%sql
7.2.8. Knock 8: 選択6#
レシート明細のテーブル(receipt)から以下の条件を満たすレコードをすべて抽出するSQL文を書け.
顧客IDが”CS018205000001”
商品コードが”P071401020”以外
ただし,表示する列およびその表示順序は売上日(sales_ymd),顧客ID(customer_id),商品コード(product_cd),売上金額(amount)とする.
%%sql
7.2.9. Knock 9: 選択7#
下記SQL文について,問い合わせ結果が変わらないようORをANDに書き換えよ.
SELECT
*
FROM
store
WHERE
NOT (prefecture_cd = 13 OR floor_area > 900);
%%sql
7.2.10. Knock 10: LIKE句1#
店舗テーブル(store)から店舗コード(store_cd)が”S14”で始まるものレコードのみを抽出し,その先頭10件を表示するSQL文を書け.ただし,表示する列はstoreテーブルにある全項目とし,その表示順序もstoreテーブルに定義された順に従うとする(つまり,store_cd, store_name, …).
%%sql
7.2.11. Knock 11: LIKE句2#
店舗テーブル(store)から横浜市にある店舗に関するレコードのみを抽出し,その先頭10件を表示するSQL文を書け.ただし,表示する列はstoreテーブルにある全項目とし,その表示順序もstoreテーブルに定義された順に従うとする(つまり,store_cd, store_name, …).
%%sql
7.2.12. Knock 12: ソート1#
顧客テーブル(customer)のレコードを高年齢順にソートし,先頭10レコードを表示するSQL文を書け.ただし,表示する列はcustomerテーブルにある全項目とし,その表示順序もcustomerテーブルに定義された順に従うとする(つまり,customer_id, customer_name, …).
%%sql
7.2.13. Knock 13: ソート2#
顧客テーブル(customer)のレコードを若い順(同じ年齢の場合は誕生日が遅い順)にソートし,先頭10レコードを表示するSQL文を書け.ただし,表示する列はcustomerテーブルにある全項目とし,その表示順序もcustomerテーブルに定義された順に従うとする(つまり,customer_id, customer_name, …).
※ヒント: ORDER BYにはソートの軸となる属性を複数指定できる
%%sql
7.2.14. Knock 14: 集計1#
レシート明細テーブル(receipt)のレコード数を求めるSQL文を書け.
%%sql
7.2.15. Knock 15: 集計2#
レシート明細テーブル(receipt)中の顧客ID(customer_id)の総数(重複を除く)を求めるSQL文を書け.
%%sql
7.2.16. Knock 16: 集約演算1#
レシート明細テーブル(receipt)に対し,店舗コード(store_cd)ごとに売上金額の合計(total_amount)と売上数量の合計(total_quantity)を計算するSQL文を書け.なお,結果のレコードは売上金額の合計値の降順で並べ替え,先頭から10件を表示せよ.また,表示する列の順序は,店舗コード,売上金額の合計,売上数量の合計の順とする.
%%sql
7.2.17. Knock 17: 集約演算2(やや難)#
レシート明細テーブル(receipt)に対し,顧客ID(customer_id)ごとに最も新しい売上日と最も古い売り上げ日を求め,それらが異なる顧客IDを求めるSQL文を書け.なお,結果レコードは顧客IDの昇順に並びかえ,先頭の10件を表示するようにせよ.また,表示する項目とその表示順序は,顧客ID,最も新しい売り上げ日(latest_sales_ymd),最も古い売り上げ日(oldest_sales_ymd)とする.
%%sql
7.2.18. Knock 18: 集約演算3#
レシート明細テーブル(receipt)に対し,店舗コード(store_cd)ごとにレシート1つあたりの売上金額(amount)の平均を計算し,その平均売り上げ金額の上位5件の店舗を表示するSQL文を書け.なお,表示する項目とその表示順序は,店舗コード,平均売上金額とする.
%%sql
7.2.19. Knock 19: 集約演算4#
レシート明細テーブル(receipt)に対し,店舗コード(store_cd)ごとに売上金額(amount)の総額を計算し,売り上げ総額が800,000以上の店舗を売り上げ総額順に表示するSQL文を書け.なお,表示する項目とその表示順序は,店舗コード,売り上げ総額とする.
%%sql
7.2.20. Knock 20: 結合1#
レシート明細テーブル(receipt)と店舗テーブル(store)を内部結合し,店舗テーブルの店舗名(store_name)とレシート明細テーブルの全項目を表示するSQL文を書け.なお,結果レコードはsales_ymdの昇順に並び替え,その先頭の10件を表示するようにせよ.また,列の表示順序は,店舗名,レシート明細テーブルで定義された列の順序とする(つまり,store_name, sales_ymd, sales_epoch…).
%%sql
7.2.21. Knock 21: 結合2#
商品テーブル(product)とカテゴリテーブル(category)を内部結合し,カテゴリテーブルの小区分名(category_small_name)および商品テーブルの全項目を表示するSQL文を書け.なお,結果レコードはproduct_cdの昇順で並び替え,その先頭の10件を表示するようにせよ.また,列の表示順序は,カテゴリテーブルの小区分名,商品テーブルで定義された列の順序とする(つまり,category_small_name, product_cd, category_major_cd…).
%%sql
7.2.22. Knock 22: 結合3(難)#
顧客テーブル(customer)とレシート明細テーブル(receipt)から,各顧客ごとの売上金額合計を求め,先頭10件を表示するSQL文を書け.ただし,以下の条件を満たすること:
売上実績がない顧客については売上金額を0として表示させること.
顧客は性別コード(
gender_cd)が女性(1)であるものを対象とし,非会員(顧客IDが”Z”から始まるもの)は除外する表示項目とその表示順は顧客ID(
customer_id),顧客名(customer_name),売上金額合計とする表示するレコードは顧客IDの昇順とする
※ヒント: IFNULL(変数1, 0)関数は,変数1が空値(None)のとき0に置き換える
%%sql
7.2.23. Knock 23: 四則演算と集約演算#
レシート明細テーブル(receipt)と顧客テーブル(customer)を結合し,年代(ageから計算)ごとの売上金額(amount)の合計値を表示するSQL文を書け.ただし,表示するレコードは年代の昇順に並び替えること.また表示する項目およびその表示順は年代,売上総額とする.
なお,年代は10歳ごとの階級とすること.
%%sql
7.2.24. Knock 24: 副問い合わせ1#
レシート明細テーブル(receipt)を利用して顧客ID(customer_id)ごとの売上総額を計算し,その平均(avg_total_amount)を求めるSQL文を書け.ただし,顧客IDが”Z”から始まるのものは非会員を表すため,除外して計算すること.
%%sql
7.2.25. Knock 25: 副問い合わせ2(難)#
レシート明細テーブル(receipt)を利用して全商品の中で売上総額が上位3位の商品コード(product_cd)を求め,各店舗(store_cd)における3つの商品の売上総額を求めるSQL文を書け.ただし,結果はstore_cd列(昇順)を第1キー,product_cd列(昇順)を第2キーとしてソートし,その先頭の30件を表示するようにせよ.また,表示する項目とその表示順序は,店舗コード,商品コード,売上総額とする.
%%sql