あなたは肥り過ぎ? 痩せ過ぎ? ~カットとパーティション~
これまでの2問では、
- カット
- 集約
という2つの操作が組み込まれた演算なのです注5。1つの句の中に2つの演算が組み込まれているというのもGROUP BYに対する理解を阻む一因になっているのですが、
name | age | height | weight |
---|---|---|---|
Anderson | 30 | 188 | 90 |
Adela | 21 | 167 | 55 |
Bates | 87 | 158 | 48 |
Becky | 54 | 187 | 70 |
Bill | 39 | 177 | 120 |
Chris | 90 | 175 | 48 |
Darwin | 12 | 160 | 55 |
Dawson | 25 | 182 | 90 |
Donald | 30 | 176 | 53 |
あなたは、
これはつまり、
![図6 4つの部分集合に切り分けてそれぞれの要素数を調べる 図6 4つの部分集合に切り分けてそれぞれの要素数を調べる](/assets/images/dev/serial/01/sql_academy/0010/0010-01.jpg)
集合の要素数を調べる関数は、
SELECT SUBSTRING(name, 1, 1) AS label,
COUNT(*)
FROM Persons
GROUP BY SUBSTRING(name, 1, 1);
label COUNT(*) ------ --------- A 2 B 3 C 1 D 3
こういうGROUP BY句でカットして作られた1つひとつの部分集合は、
![図8 年齢によるカット 図8 年齢によるカット](/assets/images/dev/serial/01/sql_academy/0010/0010-02.jpg)
当然、
SELECT CASE WHEN age < 20 THEN '子供'
WHEN age BETWEEN 21 AND 69 THEN '成人'
WHEN age > 70 THEN '老人'
ELSE NULL END AS age_class,
COUNT(*)
FROM Persons
GROUP BY CASE WHEN age < 20 THEN '子供'
WHEN age BETWEEN 21 AND 69 THEN '成人'
WHEN age > 70 THEN '老人'
ELSE NULL END;
age_class COUNT(*) ---------- --------- 子供 1 成人 6 老人 2
カットしたい区分を、
さて、
BMIによるカット
健康診断などで、
- BMI = w / t2
ここで、
名前 | BMI | 分類 |
---|---|---|
Anderson | 25. | 肥満 |
Adela | 19. | 標準 |
Bates | 19. | 標準 |
Becky | 20. | 標準 |
Bill | 38. | 肥満 |
Chris | 15. | やせ |
Darwin | 21. | 標準 |
Dawson | 27. | 肥満 |
Donald | 17. | やせ |
すると、
![図10 BMIによるカットのイメージ 図10 BMIによるカットのイメージ](/assets/images/dev/serial/01/sql_academy/0010/0010-03.jpg)
まずBMIを計算しましょう。これは
SELECT CASE WHEN weight / POWER(height /100, 2) < 18.5 THEN 'やせている'
WHEN 18.5 <= weight / POWER(height /100, 2)
AND weight / POWER(height /100, 2) < 25 THEN '標準'
WHEN 25 <= weight / POWER(height /100, 2) THEN '肥満'
ELSE NULL END AS bmi,
COUNT(*)
FROM Persons
GROUP BY CASE WHEN weight / POWER(height /100, 2) < 18.5 THEN 'やせている'
WHEN 18.5 <= weight / POWER(height /100, 2)
AND weight / POWER(height /100, 2) < 25 THEN '標準'
WHEN 25 <= weight / POWER(height /100, 2) THEN '肥満'
ELSE NULL END;
BMI COUNT(*) ------------ ---------- やせている 2 標準 4 肥満 3
GROUP BY句が
年齢階級別のパーティションカット
それでは最後に、
ということは、
たとえば、
SELECT name,
age,
CASE WHEN age < 20 THEN '子供'
WHEN age BETWEEN 21 AND 69 THEN '成人'
WHEN age > 70 THEN '老人'
ELSE NULL END AS age_class,
RANK() OVER(PARTITION BY CASE WHEN age < 20 THEN '子供'
WHEN age BETWEEN 21 AND 69 THEN '成人'
WHEN age > 70 THEN '老人'
ELSE NULL END →PARTITION BY句に式を指定している
ORDER BY age) AS age_rank_in_class
FROM Persons
ORDER BY age_class, age_rank_in_class;
name age age_class age_rank_in_class -------- ----- -------- ----------------- Darwin 12 子供 1 ――――――――――――――――――――――――――――――――――――― Adela 21 成人 1 Dawson 25 成人 2 Anderson 30 成人 3 Donald 30 成人 3 Bill 39 成人 5 Becky 54 成人 6 ――――――――――――――――――――――――――――――――――――― Bates 87 老人 1 Chris 90 老人 2
結果に横棒を引いたのは、
GROUP BYが式を引数にとれる以上PARTITION BYもまた同様であるということは、