5章 データをさらに活用するためのテクニック

■■■サブクエリを使いこなす■■■

■サブクエリとは

例)

・テーブル

  item_name|item_category|action_date|user_id|price|

  ---------|-------------|-----------|-------|-----|

  コーヒー |beverage | 2019-01-29|UID0001| 280|

  緑茶 |food | 2019-01-29|UID0001| 280|

  緑茶 |food | 2019-01-30|UID0004| 200|

  コーヒー |beverage | 2019-01-30|UID0004| 750|

  砂糖 |food | 2019-01-30|UID0011| 200|

  コーヒー |beverage | 2019-01-30|UID0011| 750|

  メイプルシロップ |food | 2019-02-01|UID0011| 450|

  メイプルシロップ |food | 2019-02-02|UID0011| 450|

  ティーカップ |zakka | 2019-02-03|UID0002| 980|

  砂糖 |food | 2019-02-04|UID0006| 280|

・SQL

  SELECT

    item_name,

    item_category,

    price

  FROM

    item_purchase_log

  WHERE

    item_category = (

      SELECT

        item_category

      FROM

        item_purchase_log

      WHERE

        item_name = '緑茶'  AND  user_id ='UID0004');

・結果

  item_name|item_category|price|

  ---------|-------------|-----|

  緑茶 |food | 280|

  緑茶 |food | 200|

  砂糖 |food | 200|

  メイプルシロップ |food | 450|

  メイプルシロップ |food | 450|

  砂糖 |food | 280|


■階層を増やしたサブクエリ

例)

・SQL

  SELECT

    item_name,  AVG(price)

  FROM

    (SELECT

      item_name,  item_category,  action_date,  price

    FROM

      item_purchase_log

    WHERE

      item_category = (

        SELECT

          item_category

        FROM

          item_purchase_log

        WHERE

          item_name = '緑茶' AND user_id ='UID0004'

        )

   ) AS special_list

  GROUP BY item_name

  HAVING AVG(price) > 300;

・結果

  item_name|AVG(price)|

  ---------|----------|

  メイプルシロップ | 450.0000|


■WITH句でサブクエリを見やすく

・SQL

  WITH special_list AS(

    SELECT

      item_name, item_category, action_date, price

    FROM

      item_purchase_log

    WHERE

      item_category = (

        SELECT

          item_category

        FROM

          item_purchase_log

        WHERE

          item_name = '緑茶' AND user_id = 'UID0004')

  )

  SELECT

    item_name, AVG(price)

  FROM

    special_list

  GROUP BY

    item_name

  HAVING AVG(price) > 300;

・結果

  item_name|AVG(price)|

  ---------|----------|

  メイプルシロップ | 450.0000|


■スカラサブクエリでスカラ値を扱う

例)購買履歴テーブルから平均価格よりも高い商品名を取得

 ー WHERE句でスカラサブクエリを利用

・SQL

  SELECT

    item_name, price

  FROM

    item_purchase_log

  WHERE

    price > (

      SELECT

        AVG(price)

      FROM

        item_purchase_log);

・結果

  item_name|price|

  ---------|-----|

  コーヒー | 750|

  コーヒー | 750|

  ティーカップ | 980|

例)平均価格カラムの追加

 ー SELECT句でスカラサブクエリを使う

・SQL

  SELECT

    item_name,

    price,

    (

      SELECT

        AVG(price)

      FROM

        item_purchase_log

    ) AS avg_price

  FROM

    item_purchase_log;

・結果

  item_name|price|avg_price|

  --------|-----|---------|

  コーヒー | 280| 462.0000|

  緑茶 | 280| 462.0000|

  緑茶 | 200| 462.0000|

  コーヒー | 750| 462.0000|

  砂糖 | 200| 462.0000|

  コーヒー | 750| 462.0000|

  メイプルシロップ | 450| 462.0000|

  メイプルシロップ | 450| 462.0000|

  ティーカップ | 980| 462.0000|

  砂糖 | 280| 462.0000|


■HAVING句でスカラサブクエリを使う

例)HAVING句の中で、全体の平均価格と、カテゴリごとの平均価格を比較し、商品カテゴリごとの平均価格が高いカテゴリを抽出

・SQL

  SELECT

    item_category, AVG(price)

  FROM

    item_purchase_log

  GROUP BY

    item_category

  HAVING AVG(price) > (

    SELECT

      AVG(price)

    FROM

      item_purchase_log);

・結果

  item_category|AVG(price)|

  -------------|----------|

  beverage | 593.3333|

  zakka | 980.0000|


■相関サブクエリでサブクエリ以外のデータを参照する

相関サブクエリ:サブクエリの中で、自分自身のクエリの外側にあるクエリのテーブル/データを参照するようなサブクエリ

例)商品カテゴリごとの平均価格より高い価格の商品の抽出

・SQL

  SELECT

    item_category, item_name, price

  FROM

    item_purchase_log AS ipl1

  WHERE

    price > (

      SELECT

        AVG(price)

      FROM

        item_purchase_log AS ipl2

      WHERE

        ipl1.item_category = ipl2.item_category

      GROUP BY

        item_category);

・結果

  item_category|item_name|price|

  ------------|---------|-----|

  beverage |コーヒー | 750|

  beverage |コーヒー | 750|

  food |メイプルシロップ | 450|

  food |メイプルシロップ | 450|


■■■INとEXISTSによるデータの調査■■■

■IN述語とサブクエリを組み合わせる

例)IN述語で都道府県を指定して、そのユーザーの購買商品を表示

・テーブル

  item_purchase_log

  item_name|item_category|action_date|user_id|price|

  ---------|-------------|-----------|-------|-----|

  コーヒー |beverage | 2019-01-29|UID0001| 280|

  緑茶 |food | 2019-01-29|UID0001| 280|

  緑茶 |food | 2019-01-30|UID0004| 200|

  コーヒー |beverage | 2019-01-30|UID0004| 750|

  砂糖 |food | 2019-01-30|UID0011| 200|

  コーヒー |beverage | 2019-01-30|UID0011| 750|

  メイプルシロップ |food | 2019-02-01|UID0011| 450|

  メイプルシロップ |food | 2019-02-02|UID0011| 450|

  ティーカップ |zakka | 2019-02-03|UID0002| 980|

  砂糖 |food | 2019-02-04|UID0006| 280|

  mst_user_place

  user_id|pref_name|city_name|

  -------|---------|---------|

  UID0001|東京都 |中央区 |

  UID0002|東京都 |世田谷区 |

  UID0003|福岡県 |福岡市 |

  UID0004|東京都 |渋谷区 |

  UID0005|神奈川県 |横浜市 |

  UID0006|愛知県 |名古屋市 |

  UID0007|東京都 |北区 |

  UID0008|福岡県 |北九州市 |

  UID0009|東京都 |渋谷区 |

  UID0010|愛知県 |名古屋市 |

  UID0011|神奈川県 |川崎市 |

・SQL

  SELECT

    item_name, price

  FROM

    item_purchase_log

  WHERE

    user_id IN(

      SELECT

        user_id

      FROM

        mst_user_place

      WHERE

        pref_name = '東京都');

・結果

  item_name|price|

  ---------|-----|

  コーヒー | 280|

  緑茶 | 280|

  ティーカップ | 980|

  緑茶 | 200|

  コーヒー | 750|


■EXISTS述語でデータを検査する

 ーEXISTSでデータの有無を調べる

例)EXISTS述語で都道府県を指定して、そのユーザーの購買商品を表示

・SQL

  SELECT

    item_name, price

  FROM

    item_purchase_log AS ipl

  WHERE

    EXISTS(

      SELECT

        *

      FROM

        mst_user_place AS mup

      WHERE

           mup.pref_name = '東京都' AND mup.user_id = ipl.user_id );

・結果

  item_name|price|

  ---------|-----|

  コーヒー | 280|

  緑茶 | 280|

  ティーカップ | 980|

  緑茶 | 200|

  コーヒー | 750|


例)NOT EXISTSにより、上の例の逆の結果を求める

・SQL

  SELECT

    item_name, price

  FROM

    item_purchase_log AS ipl

  WHERE

    NOT EXISTS(

      SELECT

        *

      FROM

        mst_user_place AS mup

      WHERE

        mup.pref_name = '東京都' AND mup.user_id = ipl.user_id );

・結果

  item_name|price|

  ---------|-----|

  砂糖 | 200|

  コーヒー | 750|

  メイプルシロップ | 450|

  メイプルシロップ | 450|

  砂糖 | 280|


■■■SQLで基本統計量を求める■■■

■HAVING句で最頻値、中央値や分位数を求める

・テーブル

  store_id|sales|

  --------|-----|

  A | 4350|

  B | 550|

  C | 400|

  D | 420|

  E | 450|

  F | 420|

  G | 400|

  H | 320|

  I | 320|

  J | 400|

例)最頻値を求めるSQL

  SELECT

    sales

  FROM

    store_sales

  GROUP BY

    sales

  HAVING count(*) >= (

    SELECT

      MAX(group_count)

    FROM

      (

        SELECT

          COUNT(*) AS group_count

        FROM

          store_sales

        GROUP BY

          sales

     ) AS sq

   );

・結果

  sales|

  -----|

  400|

例)HAVING句で中央値を求めるSQL

  SELECT

    AVG(DISTINCT sales)

  FROM

    (

      SELECT

        sa1.sales

      FROM

        store_sales sa1

        JOIN

        store_sales sa2

      GROUP BY

        sa1.sales

      HAVING

        SUM(

          CASE

            WHEN sa2.sales >= sa1.sales THEN 1

            ELSE 0

          END

        ) >= COUNT(*) / 2

        AND

        SUM(

          CASE

            WHEN sa2.sales <= sa1.sales THEN 1

            ELSE 0

          END

        ) >= COUNT(*) / 2

    ) AS sq;

・結果

  AVG(DISTINCT sales)|

  -------------------|

  410.0000|

例)分位数を求めるSQL

ー店舗売上デーブルにより、まず売上の順位(Ranking)を求め、それを四分割のグループに分ける。

  SELECT

    store_id, sales, ranking,

    CASE

     WHEN sa1.ranking <= 0.25 * ( SELECT COUNT(*) FROM store_sales ) THEN 1

     WHEN sa1.ranking <= 0.5 * (SELECT COUNT(*) FROM store_sales ) THEN 2

     WHEN sa1.ranking <= 0.75 * (SELECT COUNT(*) FROM store_sales ) THEN 3

     ELSE 4

    END AS 四分位

  FROM

    ( SELECT

       s1.store_id,

       s1.sales,

       (

        SELECT

          COUNT(s2.sales)

        FROM

          store_sales AS s2

        WHERE

          s2.sales >= s1.sales

       ) ranking

     FROM

      store_sales AS s1

     ) sa1;

・結果

  store_id|sales|ranking|四分位|

  --------|-----|-------|---|

  A | 4350| 1| 1|

  B | 550| 2| 1|

  C | 400| 8| 4|

  D | 420| 5| 2|

  E | 450| 3| 2|

  F | 420| 5| 2|

  G | 400| 8| 4|

  H | 320| 10| 4|

  I | 320| 10| 4|

  J | 400| 8| 4|


■■■ログデータひとつでできるユーザー分析■■■

・テーブル

  use_id |action_date|

  -------|-----------|

  UID0001| 2019-05-24|

  UID0001| 2019-05-24|

  UID0002| 2019-05-25|

  UID0001| 2019-05-26|

  UID0003| 2019-05-27|

  UID0001| 2019-05-28|

  UID0004| 2019-05-29|

  UID0001| 2019-05-30|

  UID0005| 2019-05-30|

  UID0001| 2019-05-30|

  UID0001| 2019-05-30|

  UID0001| 2019-06-01|

  UID0001| 2019-06-02|

  UID0002| 2019-06-03|

  UID0002| 2019-06-03|

  UID0001| 2019-06-04|

  UID0003| 2019-06-04|

  UID0001| 2019-06-05|

  UID0003| 2019-06-06|

  UID0004| 2019-06-07|


例)上記テーブルから、日別でユーザーアクション数を求める

・SQL

  SELECT

    action_date AS 日付,

    COUNT(use_id) AS アクション数

  FROM

    simple_log

  GROUP BY

    action_date;

・結果

  日付 |アクション数|

  ----------|------|

  2019-05-24| 2|

  2019-05-25| 1|

  2019-05-26| 1|

  2019-05-27| 1|

  2019-05-28| 1|

  2019-05-29| 1|

  2019-05-30| 4|

  2019-06-01| 1|

  2019-06-02| 1|

  2019-06-03| 2|

  2019-06-04| 2|

  2019-06-05| 1|

  2019-06-06| 1|

  2019-06-07| 1|


例)日別でユニークユーザー数を求める

・SQL

  SELECT

    action_date AS 日付,

    COUNT(DISTINCT(use_id)) AS ユニークユーザー数

  FROM

    simple_log

  GROUP BY

    action_date

  ORDER BY

    action_date;

・結果

  日付 |ユニークユーザー数|

  ----------|---------|

  2019-05-24| 1|

  2019-05-25| 1|

  2019-05-26| 1|

  2019-05-27| 1|

  2019-05-28| 1|

  2019-05-29| 1|

  2019-05-30| 2|

  2019-06-01| 1|

  2019-06-02| 1|

  2019-06-03| 1|

  2019-06-04| 2|

  2019-06-05| 1|

  2019-06-06| 1|

  2019-06-07| 1|


例)日別で新規ユーザー数を求める

・SQL

  SELECT

    first_action_date AS 新規登録日,

    COUNT(use_id) AS 新規ユーザー数

  FROM

    (

      SELECT

        use_id,

        MIN(action_date) AS first_action_date

      FROM

        simple_log

      GROUP BY

        use_id

    ) AS t

  GROUP BY

    first_action_date

  ORDER BY

    first_action_date;

・結果

  新規登録日 |新規ユーザー数|

  ----------|-------|

  2019-05-24| 1|

  2019-05-25| 1|

  2019-05-27| 1|

  2019-05-29| 1|

  2019-05-30| 1|


例)サービス利用継続期間毎のユーザー数を求める

・SQL

  SELECT

    action_term AS 継続期間,

    COUNT(use_id) AS ユニークユーザー数

  FROM

    (

      SELECT

        use_id,

        DATEDIFF(MAX(action_date), MIN(action_date)) AS action_term

      FROM

        simple_log

      GROUP BY

        use_id

    ) AS t

  GROUP BY

    action_term

  ORDER BY

    action_term;

・結果

  継続期間|ユニークユーザー数|

  ----|---------|

  0| 1|

  9| 2|

  10| 1|

  12| 1|


例)アクション数が3回以上のユーザーリストを求める

・SQL

  SELECT

    use_id,

    action_count AS アクション数

  FROM

    (

      SELECT

        use_id,

        COUNT(use_id) AS action_count

      FROM

        simple_log

      GROUP BY

        use_id

    ) AS t

  WHERE

    action_count >= 3;

・結果

  use_id |アクション数|

  -------|------|

  UID0001| 11|

  UID0002| 3|

  UID0003| 3|


例)直近7日間でアクション数が3回以上のユーザーリスト(直近日:2019-06-08)

・SQL

  SELECT

    use_id,

    action_count AS アクション数

  FROM

    (

      SELECT

        use_id,

        COUNT(use_id) AS action_count

      FROM

        simple_log

      WHERE

        DATEDIFF('2019-06-08', action_date) <= 7

      GROUP BY

        use_id

    ) AS t

  WHERE

    action_count >= 3;

・結果

  use_id |アクション数|

  -------|------|

  UID0001| 4|









機械学習Tips保管庫

データ解析、機械学習のための学習内容の保管庫。復習用。

0コメント

  • 1000 / 1000