デスぺR5午後2問1設問2の(3)の解釈と答え
依頼2を理解する必要がある
表1の依頼2
→出庫の頻度をみたい
→指定した物流拠点、期間
→棚別に集計した出庫回数が多い順に順位づけ
→上位20%を「高」、高を除く上位50%を「中」、それ以外を「低」
code:sql
WITH S1 AS (
SELECT S.拠点#, SM.棚#
FROM 出庫 S
INNER JOIN 出庫明細 SM ON S.拠点# = SM.拠点# AND S.出庫# = SM.出庫#
WHERE S.拠点# = :hv1 AND S.出庫年月日 BETWEEN :hv2 AND :hv3
)
on 拠点と出庫で、出庫と出庫明細んをinner join
更に拠点と出庫年月日の期間を指定
code:sql
WITH S1 AS (
SELECT S.拠点#, SM.棚#
FROM 出庫 S
INNER JOIN 出庫明細 SM ON S.拠点# = SM.拠点# AND S.出庫# = SM.出庫#
WHERE S.拠点# = :hv1 AND S.出庫年月日 BETWEEN :hv2 AND :hv3
), S2 AS (
SELECT キ AS 出庫回数
FROM 棚 T
LEFT JOIN S1 ON S1.拠点# = T.拠点# AND S1.棚# = T.棚#
WHERE T.拠点# = :hv1
ク
)
on 拠点#と棚#で、棚とs1をleft join
sunakan.iconleft joinである理由は?
→棚を優先
→出庫回数が0である棚も載る
→そして、whereで拠点を指定
キ
キは出庫回数(asで名前づけしている)
更に次のS3で、棚#が使われていることから棚#も必要
→「棚#, 〇〇 as 出庫回数」
table:サンプルデータ
T.棚# T.拠点# S1.棚# S1.拠点#
101 1 NULL NULL
102 1 102 1
count(1) as 出庫回数の場合、出庫回数が0になって欲しい棚101が、出庫回数1になってしまうのでダメ
同様の理由で、 count(T.棚#) や count(T.拠点#) でダメ
T.棚#=101のような時、出庫回数を0にしたいため、count(〇〇)にはleft join時にNULLとなるような列名である必要がある
そのため count(S1.棚#) or count(S1.拠点#) である必要がある
棚ごとの出庫回数が調べたいので、 count(S1.棚#) が自然
sunakan.iconしかし、 count(S1.拠点#) でも結果は一緒のはず(どうせASで名前づけしてるんだし)
sunakan.icon解答例は count(S1.棚#) だけだった
キ: T.棚#, count(S1.棚#)
ク
キで、countを利用していることから、group byが必要
→T.棚#をselectで利用している or 棚ごとの出庫回数が欲しい
→T.棚# でgroup by
ク: group by T.棚#
------------------------
code:sql
WITH S1 AS (
SELECT S.拠点#, SM.棚#
FROM 出庫 S
INNER JOIN 出庫明細 SM ON S.拠点# = SM.拠点# AND S.出庫# = SM.出庫#
WHERE S.拠点# = :hv1 AND S.出庫年月日 BETWEEN :hv2 AND :hv3
), S2 AS (
SELECT T.棚#, count(S1.棚#) AS 出庫回数
FROM 棚 T
LEFT JOIN S1 ON S1.拠点# = T.拠点# AND S1.棚# = T.棚#
WHERE T.拠点# = :hv1
group by T.棚#
), S3 AS (
SELECT 棚#, RANK() OVER (ケ) AS 出庫回数順位
FROM S2
)
ケ
出庫回数順位をつけたい(つけてるasより)
出庫回数でorder by descしたら良い
ケ: order by 出庫回数 desc
※ S2.出庫回数でもいいけど、テーブルはS2だけなので省略可能。棚# 指定も省略している
---------
code:sql
WITH S1 AS (
SELECT S.拠点#, SM.棚#
FROM 出庫 S
INNER JOIN 出庫明細 SM ON S.拠点# = SM.拠点# AND S.出庫# = SM.出庫#
WHERE S.拠点# = :hv1 AND S.出庫年月日 BETWEEN :hv2 AND :hv3
), S2 AS (
SELECT T.棚#, count(S1.棚#) AS 出庫回数
FROM 棚 T
LEFT JOIN S1 ON S1.拠点# = T.拠点# AND S1.棚# = T.棚#
WHERE T.拠点# = :hv1
group by T.棚#
), S3 AS (
SELECT 棚#, RANK() OVER (order by 出庫回数 desc) AS 出庫回数順位
FROM S2
)
SELECT 棚#,
CASE
WHEN (100 * コ OVER()) <= 20 THEN '高'
WHEN (100 * コ OVER()) <= 50 THEN '中'
ELSE '低'
END AS 出庫頻度区分
FROM S3
コ
FROM S3としていることから列の選択肢は「棚#」「出庫回数順位」の2つしかない
欲しいやつが出庫回数順位の上位N%とかなんだから
「出庫回数順位」となる
※ 棚# とした場合、101や708とかになるため、おかしくなる(全部「低」とかになる)
全体を100%とした時の上位N%であるため少し加工が必要
全体が10個の時、順位が1位は上位10%以内ということになる
100 * 1だと100になってしまいおかしくなる
順位/全体数となる
100 * 1 / 全体数 としたいため
over()を利用していることから count(*) が使える
コ: 出庫回数順位/count(*)
sunakan.icon個人的にはcount(1)が好みだけど、どっちでも良い
sunakan.iconRANK() OVER ()みたいな構文を知っている必要がある
sunakan.iconover()でgroup byしなくてもcount(*)が使えることを知っている必要がある