狠狠撸

狠狠撸Share a Scribd company logo
こんなデータが欲しい時、
SQLはこう書く
小林芳樹
自己紹介
名前:小林芳樹(@ykyk1218)
Qiita:https://qiita.com/ykyk1218
話すこと
1. 日付と算術演算子
2. じゃない方クエリ
3. 丑补惫颈苍驳に気をつけろ
の3本です
前提
orders
users
items
item_ma
sters1対多 多対1 多対1
多
対
1
order_de
tails
データベースはMySQL
商品
phonecase: スマホケース
walletphonecase:手帳型スマホケース
bettery:モバイルバッテリー
話すこと
1. 日付と算術演算子
2. じゃない方クエリ
3. 丑补惫颈苍驳に気をつけろ
日付と算術演算子
お題1
注文日が2018年1月8日から2018年1月23日までの
データが欲しい
2018年1月8日から2018年1月23日までのデータ
select * from orders
where date(created_at)>='2018-01-08' AND
date(created_at) <= '2018-01-23';
悪くない
2018年1月8日から2018年1月23日までのデータ
select * from orders
where created_at
between '2018-01-08' AND '2018-01-23';
ダメ
2018年1月8日から2018年1月23日までのデータ
良い
select * from orders
where created_at >= '2018-01-08' AND
created_at < '2018-01-24';
日付と算術演算子
お題2
消費税込みの価格で、1000円以上の商品を取得す
る
消費税込みの価格(price)で1000円以上の商品
select * from items i
where i.price*1.08 > 1000
悪くない
消費税込みの価格(price)で1000円以上の商品
select * from items i
where i.price > 1000 / 1.08
良い
1. 日付と算術演算子
2. じゃない方クエリ
3. 丑补惫颈苍驳に気をつけろ
話すこと
じゃない方クエリ
お題
まだ購入されていない商品を取得する
まだ購入されていない商品を取得する
あまりよくない...かも
select i.id, i.sti_type from items i
where i.id not in
(select item_id from order_details)
まだ購入されていない商品を取得する
全注文詳細データを取得するサブクエリ
select i.id, i.sti_type from items i
where i.id not in
(select item_id from order_details)
まだ購入されていない商品を取得する
select i.id, i.sti_type from items i
where not exists
(select od.id from order_details od where
od.item_id=i.id)
まだ購入されていない商品を取得する
select i.id, i.sti_type from items i
LEFT JOIN order_details od ON i.id=od.item_id
where od.item_id is NULL
じゃない方クエリ 応用編
スマホケースを買ったが、バッテリーを買っていない
顧客のリスト
前提
orders
users
items
item_ma
sters1対多 多対1 多対1
多
対
1
order_de
tails
データベースはMySQL
パターン1
select u.id, u.email from users u where
( 1 =
(case when u.id not in
(select o.user_id from orders o INNER JOIN order_details od ON
o.id=od.order_id INNER JOIN items i ON od.item_id=i.id where
i.sti_type='phonecase')
then 0
when u.id in
(select o.user_id from orders o INNER JOIN order_details od ON
o.id=od.order_id INNER JOIN items i ON od.item_id=i.id where
i.sti_type='battery')
then 0 else 1 end)
);
select u.id, u.email from users u where
( 1 =
(case when u.id not in
(select o.user_id from orders o INNER JOIN order_details od ON
o.id=od.order_id INNER JOIN items i ON od.item_id=i.id where
i.sti_type='phonecase')
then 0
when u.id in
(select o.user_id from orders o INNER JOIN order_details od ON
o.id=od.order_id INNER JOIN items i ON od.item_id=i.id where
i.sti_type='battery')
then 0 else 1 end)
);
phonecaseを注文していないユーザーを取得
select u.id, u.email from users u where
( 1 =
(case when u.id not in
(select o.user_id from orders o INNER JOIN order_details od ON
o.id=od.order_id INNER JOIN items i ON od.item_id=i.id where
i.sti_type='phonecase')
then 0
when u.id in
(select o.user_id from orders o INNER JOIN order_details od ON
o.id=od.order_id INNER JOIN items i ON od.item_id=i.id where
i.sti_type='battery')
then 0 else 1 end)
);
batteryを注文したユーザーを取得
select u.id, u.email from users u where
( 1 =
(case when u.id not in
(select o.user_id from orders o INNER JOIN order_details od ON
o.id=od.order_id INNER JOIN items i ON od.item_id=i.id where
i.sti_type='phonecase')
then 0
when u.id in
(select o.user_id from orders o INNER JOIN order_details od ON
o.id=od.order_id INNER JOIN items i ON od.item_id=i.id where
i.sti_type='battery')
then 0 else 1 end)
);
パターン2
select u.id, u.email from users u where u.id in (
select o.user_id from orders o
INNER JOIN order_details od ON o.id=od.order_id
INNER JOIN items i ON od.item_id=i.id
INNER JOIN users u ON o.user_id=u.id
WHERE i.sti_type='phonecase'
) AND u.id not in (
select o.user_id from orders o
INNER JOIN order_details od ON o.id=od.order_id
INNER JOIN items i ON od.item_id=i.id
INNER JOIN users u ON o.user_id=u.id
WHERE i.sti_type='battery'
)
select u.id, u.email from users u where u.id in (
select o.user_id from orders o
INNER JOIN order_details od ON o.id=od.order_id
INNER JOIN items i ON od.item_id=i.id
INNER JOIN users u ON o.user_id=u.id
WHERE i.sti_type='phonecase'
) AND u.id not in (
select o.user_id from orders o
INNER JOIN order_details od ON o.id=od.order_id
INNER JOIN items i ON od.item_id=i.id
INNER JOIN users u ON o.user_id=u.id
WHERE i.sti_type='battery'
)
select u.id, u.email from users u where u.id in (
select o.user_id from orders o
INNER JOIN order_details od ON o.id=od.order_id
INNER JOIN items i ON od.item_id=i.id
INNER JOIN users u ON o.user_id=u.id
WHERE i.sti_type='phonecase'
) AND u.id not in (
select o.user_id from orders o
INNER JOIN order_details od ON o.id=od.order_id
INNER JOIN items i ON od.item_id=i.id
INNER JOIN users u ON o.user_id=u.id
WHERE i.sti_type='battery'
)
1. 日付と算術演算子
2. じゃない方クエリ
3. 丑补惫颈苍驳に気をつけろ
話すこと
having に気をつけろ
お題
手帳型スマホケースの購入回数が
5回より少ないユーザーを取得
select u.id, count(o.id) from orders o
INNER JOIN order_details od ON
o.id=od.order_id
INNER JOIN users u ON o.user_id=u.id
INNER JOIN items i ON od.item_id=i.id
where i.sti_type='walletphonecase'
group by u.id
having count(o.id) < 5
何が問題か
0件のデータが取得できない
select u.email, count(order_filter.order_id) from
users u
LEFT OUTER JOIN
(select o.id oid, o.user_id uid from orders o
INNER JOIN order_details od ON
o.id=od.order_id
INNER JOIN items i ON od.item_id=i.id
where i.sti_type='walletphonecase'
) order_filter ON order_filter.user_id = u.id
group by u.id
having count(order_filter.oid) < 5
order by count(order_filter.oid)
select u.email, count(order_filter.order_id) from
users u
LEFT OUTER JOIN
(select o.id oid, o.user_id uid from orders o
INNER JOIN order_details od ON
o.id=od.order_id
INNER JOIN items i ON od.item_id=i.id
where i.sti_type='walletphonecase'
) order_filter ON order_filter.user_id = u.id
group by u.id
having count(order_filter.oid) < 5
order by count(order_filter.oid)
外部結合でJOINをして注文していないユーザーも取
得する
select u.email, count(order_filter.order_id) from
users u
LEFT OUTER JOIN
(select o.id oid, o.user_id uid from orders o
INNER JOIN order_details od ON
o.id=od.order_id
INNER JOIN items i ON od.item_id=i.id
where i.sti_type='walletphonecase'
) order_filter ON order_filter.user_id = u.id
group by u.id
having count(order_filter.oid) < 5
order by count(order_filter.oid)
count(*)だと0件の要素がカウント
されない
まとめ
where句で比較対象のカラムに関数や計算式を使うとインデック
スが効かなくなる
商品Aを購入して、商品Bを購入していないユーザーのリストは
where in(where not in)の条件分にサブクエリをつかって
取得できる
having < count(x)を使う場合は0件の場合にヒットしない可能
性があるので気をつける。対応するには外部結合を使う

More Related Content

こんなデータが欲しい时、厂蚕尝はこう书く