このページは、世界最大級のオンライン学習プラットフォームUdemy(ユーデミー)とProglus(プログラス)にて公開している、「はじめてのSQL・データ分析入門」、及び、Proglus(プログラス)にて公開中の「はじめてのSQL ・データ分析入門」 受講生の方向けサポートサイトです。
よくあるご質問、及び、コースで実行するSQL一覧をテキストで掲載しています(一部除く)。
エラーが発生した時に見比べたり、動作するSQLをコピー&ペースとして実行したいときなど、個人の学習用にご利用ください。
MySQL 5.7(.21)、MySQL8.0にて動作確認をしております。その他の環境では動作が異なる場合があります。
目次
- 1 よくあるご質問
- 2 サンプルコード(SQL)
- 3 列を指定してデータを取得する select
- 4 列の値に対して演算を行う
- 4.1 条件を指定してデータを取得する where
- 4.2 比較演算子の種類
- 4.3 パターンマッチングによる絞込 like
- 4.4 取得件数を制限する limit
- 4.5 演習回答:取得件数を制限する limit句
- 4.6 合計値を求める sum集約関数
- 4.7 平均値を求める avg集約関数
- 4.8 最小値を求める min集約関数
- 4.9 最大値を求める max集約関数
- 4.10 対象行の行数を数える count集約関数
- 4.11 応用:月間ユニークユーザー数を求める
- 4.12 データをグループ化 group by
- 4.13 集計をさらに絞り込む having
- 4.14 演習:データの集約
- 4.15 並び替え order by
- 4.16 複数の並び替え条件を指定する
- 4.17 演習回答:データの並び替え
- 4.18 いろいろな算術演算子
- 4.19 nullを含む演算
- 4.20 絶対値の取得 abs
- 4.21 四捨五入 round
- 4.22 文字列の演算
- 4.23 演習回答: 文字列の演算 メルマガ送信用のリスト作成
- 4.24 日付と時刻の演算
- 4.25 内部結合でテーブルを結合する inner join
- 4.26 内部結合 + 絞り込み
- 4.27 演習回答:内部結合
- 4.28 外部結合 left outer join
- 4.29 応用:すべての商品について、販売個数一覧を出力
- 4.30 3つ以上のテーブルを使った結合
- 4.31 多対多の関係を含む結合
- 4.32 テーブルの足し算 union, union all
- 4.33 ビューの作成
- 4.34 ビューの削除
- 5 サブクエリ(where句)
- 6 応用:全商品の平均単価より、高い商品を取得
- 7 応用問題
- 8 データの更新
- 9 注意事項
よくあるご質問
Q. MySQL Workbenchで使えるショートカットを教えてください。
A. 下記の記事を参照してください。
– MySQL Workbenchの便利なショートカット
Q. MySQL 5.7/8.0 for macOSのアンインストール方法を教えてください
A. サポート記事「macOSにHomebrewでインストールしたMySQL5.7, MySQL8.0をアンインストールする方法」を参照してください。
Q. MySQL 5.7 for Windowsのアンインストール方法を教えてください
A. サポート記事「MySQL 5.7 for Windowsのアンインストール方法」を参照してください。
サンプルコード(SQL)
SQL文の基礎
/* データベースの選択 */ use mydb; /* ユーザー一覧の取得 */ select * from users;
演習回答:データを取り出す
select * from products;
コメント
-- select * from users; /* select * from users; select * from products */
よくあるSQLのエラー
select name, price from products; -- DB選択していない use mydb; select * from users; -- スペルミス select * form users; -- 全角文字 select * from users;
列を指定してデータを取得する select
select id, last_name from users;
補足: SQLの書き方
select id, last_name from users;
select
id,
last_name
from
users;
SELECT ID, LAST_NAME FROM USERS;
SELECT id, last_name FROM users;
SELect ID, LAst_NAme FroM USers;
select id, last_name from users LIMIT 0, 1000;
演習回答:列を指定してデータを取得する
select name, price from products;
select name, price from products;
select name as 名前, price as 価格 from products;
select name 名前, price 価格 from products;
列に別名をつける
select name, price from products; select name as 名前, price as 価格 from products; select name 名前, price 価格 from products;
列の値に対して演算を行う
select
name as 名前,
price as 価格,
price * 1.08 as 税込価格
from
products;
条件を指定してデータを取得する where
select name, price from products where price >= 9800;
比較演算子の種類
-- 1) products テーブルから全件取得 select * from products; -- 2) idが1の行を取得 select * from products where id = 1; -- 3) 名前が「商品0003」の行を取得 select * from products where name = '商品0003'; -- 4) priceが1000より大きい行を取得 select * from products where price > 1000; -- 5) price が1000より小さい行を取得 select * from products where price < 1000; -- 6) priceが100でない行を取得 select * from products where price <> 100; -- 7) 次のようにもかけます。 select * from products where price != 100; -- 8) idが1か2か3の行を取得 select * from products where id in(1, 2, 3); -- 9)idが1か2か3ではない行を取得 select * from products where id not in(1, 2, 3); -- 10)priceがnullではない行を取得 select * from products where price is not null; -- 11)priceがnullの行を取得 select * from products where price is null; -- 12)priceが1000から1900の行を取得 select * from products where price between 1000 and 1900; -- 13)これは次のようandを使っても書ける。andは、論理積。条件AもBも成り立つ時にtrue(真)。 select * from products where price >= 1000 and price <= 1900; -- 14)or (論理和)も使える。条件Aか条件Bが一つ以上成り立つ場合にtrue -- 価格が1000円又は2000円の行を取得 select * from products where price = 1000 or price = 2000;
パターンマッチングによる絞込 like
select * from users where last_name like '中%'; select * from users where last_name like '%中%'; select * from users where first_name like '%子'; select * from users where first_name like '__子';
取得件数を制限する limit
select * from products limit 10; select * from products limit 0, 10; select * from products limit 10, 10;
演習回答:取得件数を制限する limit句
select id, last_name, gender from users where gender = 1 limit 10;
合計値を求める sum集約関数
-- select * from orders;
select
sum(amount)
from
orders
where
order_time >= '2017-01-01 00:00:00'
and order_time < '2017-02-01 00:00:00';
平均値を求める avg集約関数
-- select * from products; select avg(price) from products;
最小値を求める min集約関数
select min(price) from products;
最大値を求める max集約関数
select max(price) from products;
対象行の行数を数える count集約関数
-- select * from users; -- select count(*) from users; select count(*) from users where gender = 2;
応用:月間ユニークユーザー数を求める
-- select * from access_logs;
select
count(distinct user_id)
from
access_logs
where
request_month = '2017-01-01';
データをグループ化 group by
select
prefecture_id,
count(*)
from
users
group by
prefecture_id;
### 応用 : 期間ごとに集計する
select
request_month,
count(distinct user_id)
from
access_logs
where
request_month >= '2017-01-01'
and request_month < '2018-01-01'
group by
request_month;
集計をさらに絞り込む having
select
request_month,
count(distinct user_id)
from
access_logs
where
request_month >= '2017-01-01'
and request_month < '2018-01-01'
group by
request_month
having
count(distinct user_id) >= 630;
演習:データの集約
-- select * from access_logs;
select
request_month,
count(*)
from
access_logs
where
request_month >= '2017-01-01'
and request_month < '2017-07-01'
group by
request_month
having
count(*) >= 1000;
並び替え order by
-- select * from products order by price desc; -- select * from products order by price asc; select * from products order by price;
複数の並び替え条件を指定する
select * from products order by price desc, id asc; select * from products order by price desc, id;
演習回答:データの並び替え
-- 演習 -- ユーザー一覧を、出力。 -- 生年月日が古いに並べる。 -- 生年月日が一緒の場合は、都道府県ID順(昇順)に並べる。 -- select * from users order by birthday asc, prefecture_id asc; select * from users order by birthday, prefecture_id;
いろいろな算術演算子
/* 足し算 */ select 10 + 3; /* 引き算 */ select 10 - 3; /* 掛け算 */ select 10 * 3; /* 割り算 */ select 10 / 3; /* 余り */ select 10 % 3;
nullを含む演算
/* 足し算 */ select 10 + null; /* 引き算 */ select 10 - null; /* 掛け算 */ select 10 * null; /* 割り算 */ select 10 / null; /* 余り */ select 10 % null;
絶対値の取得 abs
/* 10の絶対値 */ select abs(10); /* -10の絶対値 */ select abs(-10); /* 0の絶対値 */ select abs(0);
四捨五入 round
/* 商品価格一覧を作成する時に、税込み価格を出力してほしい。 ただし、小数第1位で四捨五入して出力 */ select id, name, price * 1.08 from products; select id, name, round(price * 1.08, 0) from products; select round(10.555, 0); select round(10.555, 1); select round(10.555, 2);
文字列の演算
/*ユーザー一覧を、 山田 太郎さん というように 名字+スペース+ 名前 + さん の、フォーマットで出力してほしい*/ select concat(last_name, ' ', first_name, 'さん') from users;
演習回答: 文字列の演算 メルマガ送信用のリスト作成
/* 演習 : メルマガ送信用のリスト作成 出力項目は、 宛名「名字 + さん」 メールアドレス 例)中村さん, nakamura@example.com 女性だけに送信したい */ select concat(last_name, 'さん'), email from users where gender = 2;
日付と時刻の演算
/* 現在の日付 ・・・ current_date */ select current_date(); /* 現在の時刻 ・・・ current_timestamp */ select current_timestamp(); /* n日後の日付 ・・・ interval */ select current_date() + interval 3 day; /* n日前の日付 ・・・ interval */ select current_date() - interval 3 day; /* x時間後の時刻 ・・・ interval 'x hour' */ select current_time() + interval 6 hour; /* x時間前の時刻 ・・・ - interval 'x hour' */ select current_time() - interval 6 hour; ### 日付と時刻の演算 /* extract ・・・ 日付や時刻の特定の部分(年や月)までを取り出す。 */ /* ordersテーブルから注文日時(order_timeカラム)が、2017年01月のレコードを取得する。*/ select * from orders where extract(year_month from order_time) = 201701; /* ordersテーブルから注文日時(order_timeカラム)が、2017年のレコードを取得する。*/ select * from orders where extract(year from order_time) = 2017; /* ordersテーブルから注文日時(order_timeカラム)が、1 月のレコードを取得する。*/ select * from orders where extract(month from order_time) = 1;
内部結合でテーブルを結合する inner join
/* 顧客一覧を取得して欲しい。
都道府県IDで出力されてもよくわからないので、都道府県名も表示してほしい。
必要な列は、ユーザーID, 名字, 名前, 都道府県名。*/
/*
select
users.id,
users.last_name,
users.first_name,
prefectures.name
from
users
inner join
prefectures
on users.prefecture_id = prefectures.id;*/
select
u.id,
u.last_name,
u.first_name,
p.name
from
users u
inner join
-- join
prefectures p
on u.prefecture_id = p.id;
内部結合 + 絞り込み
/* 顧客一覧を取得して欲しい。
都道府県IDで出力されてもよくわからないので、都道府県名も表示してほしい。
必要列は、ユーザーID, 名字, 名前, 都道府県名。
【追加条件】
女性だけのデータが欲しい */
select
u.id,
u.last_name,
u.first_name,
p.name
from
users u
inner join
prefectures p
on u.prefecture_id = p.id
where u.gender = 2;
演習回答:内部結合
/* 2017年1月の、東京都に住むユーザーの、注文情報一覧を出して。
取得する列(カラム)は、
注文id (orders.id)
注文日時(orders.order_time)
注文金額合計(orders.amount)
ユーザーid (user.id)
名字(users.last_name)
名前(users.first_name) */
select
o.id order_id,
o.order_time order_time,
o.amount amount,
u.id user_id,
u.last_name last_name,
u.first_name first_name
from
orders o
inner join
users u
on o.user_id = u.id
where
u.prefecture_id = 13
and o.order_time >= '2017-01-01 00:00:00'
and o.order_time < '2017-02-01 00:00:00'
order by order_id;
外部結合 left outer join
/* usersテーブルとordersテーブルを結合 */
select
u.last_name last_name,
u.id user_id,
o.user_id order_user_id,
o.id order_id
from
users u
-- inner join
-- left outer join
left join
orders o
on u.id = o.user_id
order by u.id;
応用:すべての商品について、販売個数一覧を出力
/* すべての商品について、販売個数一覧を出して */
select
p.id,
p.name,
sum(od.product_qty) num
from
products p
left outer join
-- inner join
order_details od
on p.id = od.product_id
group by p.id
;
3つ以上のテーブルを使った結合
/* 注文一覧を出して欲しい。
注文詳細情報と商品情報も一覧の中に入れて欲しい。*/
select
o.id order_id,
o.user_id user_id,
u.last_name last_name,
u.first_name first_name,
o.amount amount,
o.order_time order_time,
p.name product_name,
od.product_qty qty,
p.price product_price
from
orders o
inner join
order_details od
on o.id = od.order_id
inner join
products p
on od.product_id = p.id
inner join
users u
on o.user_id = u.id;
多対多の関係を含む結合
select
p.id product_id,
p.name product_name,
c.name category_name
from products p
inner join products_categories pc
on p.id = pc.product_id
inner join categories c
on c.id = pc.category_id
where p.id = 3;
テーブルの足し算 union, union all
/* ユーザーと、アドミンユーザーを足し合わせた一覧が欲しい
出力して欲しい列は、
email
姓
名
性別(性別を表す数字でOK) */
/*
select
email,
last_name,
first_name,
gender
from
users
union all
select
email,
last_name,
first_name,
gender
from
admin_users;*/
select
email,
last_name,
first_name,
gender
from
users
where
gender = 1
union all
select
email,
last_name,
first_name,
gender
from
admin_users
where
gender = 2
order by gender;
ビューの作成
/* 都道府県別のユーザー数を教えて。*/
/*create view prefecture_user_counts(name, count)
as
select
p.name name,
count(*) count
from
users u
inner join
prefectures p
on u.prefecture_id = p.id
group by
u.prefecture_id;*/
select
name,
count
from
prefecture_user_counts;
ビューの削除
drop view prefecture_user_counts; select name, count from prefecture_user_counts;
サブクエリ(where句)
select
id,
last_name,
email
from
users
where id not in(
select
user_id
from
orders
where
order_time >= '2017-12-01 00:00:00'
and order_time < '2018-01-01 00:00:00');
演習回答:サブクエリ
select
id,
last_name,
email
from
users
where id in(
select
user_id
from
orders
where
order_time >= '2017-12-01 00:00:00'
and order_time < '2018-01-01 00:00:00');
応用:全商品の平均単価より、高い商品を取得
select
*
from
products
where
price >
(
select
avg(price)
from
products
)
order by
price desc, id;
条件によって値を変更する
/*ユーザーのアクティビティの度合いによって、施策を変えたい、
ユーザーを累計注文回数で、ランク分けして。
A : 5回以上
B : 2回以上 (2 or 3 or 4)
C : 1回
※注文回数0回のユーザーは出力不要。
必要情報:
ユーザーID
累計注文回数
ユーザーランク(A or B or C) */
select
u.id as user_id,
count(*) as num,
case
when count(*) >= 5 then 'A'
when count(*) >= 2 then 'B'
else 'C'
end as user_rank
from
users as u
inner join
orders as o
on u.id = o.user_id
group by u.id
order by user_rank
;
取得値nullを0を置き換える
select
p.id,
p.name,
case
when sum(od.product_qty) is null then 0
else sum(od.product_qty)
end as num
from
products p
left outer join
order_details od
on p.id = od.product_id
group by p.id;
演習回答:商品を販売個数でランク分け
/*全商品を累計販売個数で、ランク分けして欲しい。
A : 20個以上
B : 10個以上
C : 10個未満
ランクが高い順に、並び替えて。
必要な列は、商品ID、商品名、販売個数、ランク(A or B or C)*/
select
p.id,
p.name,
sum(product_qty),
case
when sum(product_qty) >= 20 then 'A'
when sum(product_qty) >= 10 then 'B'
else 'C'
end as product_rank
from
products p
left outer join
order_details od
on p.id = od.product_id
group by p.id
order by product_rank
;
応用問題
平均客単価
/*全期間での平均客単価を教えて
補足:単価は小数第一位で四捨五入*/
select
round(avg(amount), 0)
from
orders;
月別平均客単価
/*月別の平均客単価を教えて
補足
小数第一位で四捨五入。
必要な列
年月
平均客単価*/
select
date_format(order_time, '%Y%m') as order_year_month,
round(avg(amount), 0) as average_customer_spend
from
orders
group by
date_format(order_time, '%Y%m')
order by order_year_month
;
都道府県別平均客単価
/*都道府県別平均客単価を教えてほしい。
必要な列
都道府県ID
都道府県名
平均客単価(小数第1位で四捨五入)
並び順
都道府県ID昇順
全期間での平均客単価を教えて*/
select
pref.id as prefecture_id,
pref.name as prefecture_name,
round(avg(o.amount), 0) as average_customer_spend
from
orders o
inner join users u
on o.user_id = u.id
inner join prefectures pref
on u.prefecture_id = pref.id
group by
pref.id
order by
pref.id
;
都道府県別・月別平均客単価
/* 都道府県別・月別平均客単価を教えて
必要な列
都道府県ID
都道府県名
年月
平均客単価(小数第1位で四捨五入)
並び順
都道府県ID昇順, 年月昇順 */
select
pref.id as prefecture_id,
pref.name as prefecture_name,
date_format(o.order_time, '%Y%m') as order_year_month,
round(avg(o.amount), 0) as average_customer_spend
from
orders o
inner join users u
on o.user_id = u.id
inner join prefectures pref
on u.prefecture_id = pref.id
group by
prefecture_id, order_year_month
order by
prefecture_id, order_year_month
;
データの更新
レコードを1件追加する insert
insert into products (name, price) values ('新商品A', 1000);
select * from products;
列リストを省略して1件行を追加する
select * from products; insert products values(1002, '新商品B', 2000); select * from products;
行を複数追加する
/*新商品を3件データベースに追加してほしい。 */
商品名:新商品C
価格:3,000
商品名:新商品D
価格:4,000
商品名:新商品E
価格:5,000*/
insert into
products (name, price)
values
('新商品C', 3000),
('新商品D', 4000),
('新商品E', 5000);
select * from products;
行の更新 update
/* 全商品を10%引きに設定して。*/ select * from products; set sql_safe_updates = 0; update products set price = price * 0.9; select * from products;
特定の条件に合致する行を更新 update
/* 商品idが3の商品名を、「SQL入門」に変えておいて。*/ select * from products where id = 3; update products set name = 'SQL入門' where id = 3; select * from products where id = 3; update products set name = 'SQL入門1', price = 1000 where id = 3; select * from products where id = 3;
更新条件にサブクエリを使う
/*累計販売数が10個以上の商品については、
価格を5%UPして。*/
select
product_id,
sum(product_qty)
from
order_details
group by
product_id
having
sum(product_qty) >= 10;
select * from products;
update
products
set
price = price * 1.05
where
id in
(
select
product_id
from
order_details
group by
product_id
having
sum(product_qty) >= 10
);
select * from products;
行の削除
/*今、商品に割り振られている商品カテゴリを使うのをやめるので、 商品とカテゴリのひも付きを削除してほしい*/ select * from products_categories; delete from products_categories; select * from products_categories;
条件を指定して、行の削除
/* 商品ID 1001は、 間違いで登録してしまったものだから、削除してほしい。*/ select * from products where id = 1001; delete from products where id = 1001; select * from products where id = 1001;
削除条件にサブクエリを使う
/* 一個も売れていない商品は、売るのをやめるので削除して。*/
select
product_id
from
order_details
group by
product_id;
delete
from
products
where
id not in(
select
product_id
from
order_details
group by
product_id
);
select * from products;
データベースの作成
show databases; create database book_store; show databases;
テーブルの追加
use book_store; show tables; create table books(id int not null auto_increment primary key, title varchar(255) not null); show tables; show columns from books;
テーブル構造の変更
show columns from books; alter table books add price int after id; show columns from books; alter table books change price unit_price int; show columns from books; alter table books drop unit_price; show columns from books;
テーブルの削除
show tables; drop table books; show tables;
データベースの削除
show databases; drop database book_store; show databases;
注意事項
受講生の皆さんの個人的な学習にのみご利用いただけます。
営利・非営利問わず二次利用する行為を禁止します。